?????????? ????????? - ??????????????? - /home/agenciai/public_html/cd38d8/algorithms.tar
???????
default_area_result.hpp 0000644 00000002401 15125631656 0011276 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_STRATEGY_DEFAULT_AREA_RESULT_HPP #define BOOST_GEOMETRY_STRATEGY_DEFAULT_AREA_RESULT_HPP #include <boost/geometry/algorithms/area_result.hpp> namespace boost { namespace geometry { /*! \brief Meta-function defining return type of area function, using the default strategy \ingroup area \note The strategy defines the return-type (so this situation is different from length, where distance is sqr/sqrt, but length always squared) */ template <typename Geometry> struct default_area_result : area_result<Geometry> {}; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGY_DEFAULT_AREA_RESULT_HPP buffer.hpp 0000644 00000020731 15125631656 0006543 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP #define BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP #include <cstddef> #include <boost/numeric/conversion/cast.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Input, typename Output, typename TagIn = typename tag<Input>::type, typename TagOut = typename tag<Output>::type > struct buffer: not_implemented<TagIn, TagOut> {}; template <typename BoxIn, typename BoxOut> struct buffer<BoxIn, BoxOut, box_tag, box_tag> { template <typename Distance> static inline void apply(BoxIn const& box_in, Distance const& distance, Distance const& , BoxOut& box_out) { detail::buffer::buffer_box(box_in, distance, box_out); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct buffer { template <typename Distance, typename GeometryOut> static inline void apply(Geometry const& geometry, Distance const& distance, Distance const& chord_length, GeometryOut& out) { dispatch::buffer<Geometry, GeometryOut>::apply(geometry, distance, chord_length, out); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct buffer<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Distance, typename GeometryOut> struct visitor: boost::static_visitor<void> { Distance const& m_distance; Distance const& m_chord_length; GeometryOut& m_out; visitor(Distance const& distance, Distance const& chord_length, GeometryOut& out) : m_distance(distance), m_chord_length(chord_length), m_out(out) {} template <typename Geometry> void operator()(Geometry const& geometry) const { buffer<Geometry>::apply(geometry, m_distance, m_chord_length, m_out); } }; template <typename Distance, typename GeometryOut> static inline void apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Distance const& distance, Distance const& chord_length, GeometryOut& out ) { boost::apply_visitor(visitor<Distance, GeometryOut>(distance, chord_length, out), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{buffer} \ingroup buffer \details \details_calc{buffer, \det_buffer}. \tparam Input \tparam_geometry \tparam Output \tparam_geometry \tparam Distance \tparam_numeric \param geometry_in \param_geometry \param geometry_out \param_geometry \param distance The distance to be used for the buffer \param chord_length (optional) The length of the chord's in the generated arcs around points or bends \qbk{[include reference/algorithms/buffer.qbk]} */ template <typename Input, typename Output, typename Distance> inline void buffer(Input const& geometry_in, Output& geometry_out, Distance const& distance, Distance const& chord_length = -1) { concepts::check<Input const>(); concepts::check<Output>(); resolve_variant::buffer<Input>::apply(geometry_in, distance, chord_length, geometry_out); } /*! \brief \brief_calc{buffer} \ingroup buffer \details \details_calc{return_buffer, \det_buffer}. \details_return{buffer}. \tparam Input \tparam_geometry \tparam Output \tparam_geometry \tparam Distance \tparam_numeric \param geometry \param_geometry \param distance The distance to be used for the buffer \param chord_length (optional) The length of the chord's in the generated arcs around points or bends (RESERVED, NOT YET USED) \return \return_calc{buffer} */ template <typename Output, typename Input, typename Distance> Output return_buffer(Input const& geometry, Distance const& distance, Distance const& chord_length = -1) { concepts::check<Input const>(); concepts::check<Output>(); Output geometry_out; resolve_variant::buffer<Input>::apply(geometry, distance, chord_length, geometry_out); return geometry_out; } /*! \brief \brief_calc{buffer} \ingroup buffer \details \details_calc{buffer, \det_buffer}. \tparam GeometryIn \tparam_geometry \tparam MultiPolygon \tparam_geometry{MultiPolygon} \tparam DistanceStrategy A strategy defining distance (or radius) \tparam SideStrategy A strategy defining creation along sides \tparam JoinStrategy A strategy defining creation around convex corners \tparam EndStrategy A strategy defining creation at linestring ends \tparam PointStrategy A strategy defining creation around points \param geometry_in \param_geometry \param geometry_out output multi polygon (or std:: collection of polygons), will contain a buffered version of the input geometry \param distance_strategy The distance strategy to be used \param side_strategy The side strategy to be used \param join_strategy The join strategy to be used \param end_strategy The end strategy to be used \param point_strategy The point strategy to be used \qbk{distinguish,with strategies} \qbk{[include reference/algorithms/buffer_with_strategies.qbk]} */ template < typename GeometryIn, typename MultiPolygon, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy > inline void buffer(GeometryIn const& geometry_in, MultiPolygon& geometry_out, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy) { typedef typename boost::range_value<MultiPolygon>::type polygon_type; concepts::check<GeometryIn const>(); concepts::check<polygon_type>(); typedef typename point_type<GeometryIn>::type point_type; typedef typename rescale_policy_type < point_type, typename geometry::cs_tag<point_type>::type >::type rescale_policy_type; geometry_out.clear(); if (geometry::is_empty(geometry_in)) { // Then output geometry is kept empty as well return; } model::box<point_type> box; geometry::envelope(geometry_in, box); geometry::buffer(box, box, distance_strategy.max_distance(join_strategy, end_strategy)); typename strategy::intersection::services::default_strategy < typename cs_tag<GeometryIn>::type >::type intersection_strategy; rescale_policy_type rescale_policy = boost::geometry::get_rescale_policy<rescale_policy_type>( box, intersection_strategy); detail::buffer::buffer_inserter<polygon_type>(geometry_in, range::back_inserter(geometry_out), distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, intersection_strategy, rescale_policy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP make.hpp 0000644 00000014405 15125631656 0006210 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_MAKE_HPP #define BOOST_GEOMETRY_ALGORITHMS_MAKE_HPP #include <type_traits> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/core/make.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace make { /*! \brief Construct a geometry \ingroup make \tparam Geometry \tparam_geometry \tparam Range \tparam_range_point \param range \param_range_point \return The constructed geometry, here: a linestring or a ring \qbk{distinguish, with a range} \qbk{ [heading Example] [make_with_range] [make_with_range_output] [heading See also] \* [link geometry.reference.algorithms.assign.assign_points assign] } */ template <typename Geometry, typename Range> inline Geometry make_points(Range const& range) { concepts::check<Geometry>(); Geometry geometry; geometry::append(geometry, range); return geometry; } }} // namespace detail::make #endif // DOXYGEN_NO_DETAIL /*! \brief Construct a geometry \ingroup make \details \note It does not work with array-point types, like int[2] \tparam Geometry \tparam_geometry \tparam Type \tparam_numeric to specify the coordinates \param c1 \param_x \param c2 \param_y \return The constructed geometry, here: a 2D point \qbk{distinguish, 2 coordinate values} \qbk{ [heading Example] [make_2d_point] [make_2d_point_output] [heading See also] \* [link geometry.reference.algorithms.assign.assign_values_3_2_coordinate_values assign] } */ template < typename Geometry, typename Type, std::enable_if_t<! traits::make<Geometry>::is_specialized, int> = 0 > inline Geometry make(Type const& c1, Type const& c2) { concepts::check<Geometry>(); Geometry geometry; dispatch::assign < typename tag<Geometry>::type, Geometry, geometry::dimension<Geometry>::type::value >::apply(geometry, c1, c2); return geometry; } template < typename Geometry, typename Type, std::enable_if_t<traits::make<Geometry>::is_specialized, int> = 0 > constexpr inline Geometry make(Type const& c1, Type const& c2) { concepts::check<Geometry>(); // NOTE: This is not fully equivalent to the above because assign uses // numeric_cast which can't be used here since it's not constexpr. return traits::make<Geometry>::apply(c1, c2); } /*! \brief Construct a geometry \ingroup make \tparam Geometry \tparam_geometry \tparam Type \tparam_numeric to specify the coordinates \param c1 \param_x \param c2 \param_y \param c3 \param_z \return The constructed geometry, here: a 3D point \qbk{distinguish, 3 coordinate values} \qbk{ [heading Example] [make_3d_point] [make_3d_point_output] [heading See also] \* [link geometry.reference.algorithms.assign.assign_values_4_3_coordinate_values assign] } */ template < typename Geometry, typename Type, std::enable_if_t<! traits::make<Geometry>::is_specialized, int> = 0 > inline Geometry make(Type const& c1, Type const& c2, Type const& c3) { concepts::check<Geometry>(); Geometry geometry; dispatch::assign < typename tag<Geometry>::type, Geometry, geometry::dimension<Geometry>::type::value >::apply(geometry, c1, c2, c3); return geometry; } template < typename Geometry, typename Type, std::enable_if_t<traits::make<Geometry>::is_specialized, int> = 0 > constexpr inline Geometry make(Type const& c1, Type const& c2, Type const& c3) { concepts::check<Geometry>(); // NOTE: This is not fully equivalent to the above because assign uses // numeric_cast which can't be used here since it's not constexpr. return traits::make<Geometry>::apply(c1, c2, c3); } template <typename Geometry, typename Type> inline Geometry make(Type const& c1, Type const& c2, Type const& c3, Type const& c4) { concepts::check<Geometry>(); Geometry geometry; dispatch::assign < typename tag<Geometry>::type, Geometry, geometry::dimension<Geometry>::type::value >::apply(geometry, c1, c2, c3, c4); return geometry; } /*! \brief Construct a box with inverse infinite coordinates \ingroup make \details The make_inverse function initializes a 2D or 3D box with large coordinates, the min corner is very large, the max corner is very small. This is useful e.g. in combination with the expand function, to determine the bounding box of a series of geometries. \tparam Geometry \tparam_geometry \return The constructed geometry, here: a box \qbk{ [heading Example] [make_inverse] [make_inverse_output] [heading See also] \* [link geometry.reference.algorithms.assign.assign_inverse assign_inverse] } */ template <typename Geometry> inline Geometry make_inverse() { concepts::check<Geometry>(); Geometry geometry; dispatch::assign_inverse < typename tag<Geometry>::type, Geometry >::apply(geometry); return geometry; } /*! \brief Construct a geometry with its coordinates initialized to zero \ingroup make \details The make_zero function initializes a 2D or 3D point or box with coordinates of zero \tparam Geometry \tparam_geometry \return The constructed and zero-initialized geometry */ template <typename Geometry> inline Geometry make_zero() { concepts::check<Geometry>(); Geometry geometry; dispatch::assign_zero < typename tag<Geometry>::type, Geometry >::apply(geometry); return geometry; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_MAKE_HPP correct.hpp 0000644 00000024160 15125631656 0006733 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP #define BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP #include <algorithm> #include <cstddef> #include <functional> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/correct_closure.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/detail/multi_modify.hpp> #include <boost/geometry/util/order_as_direction.hpp> namespace boost { namespace geometry { // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace correct { template <typename Geometry> struct correct_nop { template <typename Strategy> static inline void apply(Geometry& , Strategy const& ) {} }; template <typename Box, std::size_t Dimension, std::size_t DimensionCount> struct correct_box_loop { typedef typename coordinate_type<Box>::type coordinate_type; static inline void apply(Box& box) { if (get<min_corner, Dimension>(box) > get<max_corner, Dimension>(box)) { // Swap the coordinates coordinate_type max_value = get<min_corner, Dimension>(box); coordinate_type min_value = get<max_corner, Dimension>(box); set<min_corner, Dimension>(box, min_value); set<max_corner, Dimension>(box, max_value); } correct_box_loop < Box, Dimension + 1, DimensionCount >::apply(box); } }; template <typename Box, std::size_t DimensionCount> struct correct_box_loop<Box, DimensionCount, DimensionCount> { static inline void apply(Box& ) {} }; // Correct a box: make min/max correct template <typename Box> struct correct_box { template <typename Strategy> static inline void apply(Box& box, Strategy const& ) { // Currently only for Cartesian coordinates // (or spherical without crossing dateline) // Future version: adapt using strategies correct_box_loop < Box, 0, dimension<Box>::type::value >::apply(box); } }; // Close a ring, if not closed template <typename Ring, template <typename> class Predicate> struct correct_ring { typedef typename point_type<Ring>::type point_type; typedef typename coordinate_type<Ring>::type coordinate_type; typedef detail::area::ring_area < order_as_direction<geometry::point_order<Ring>::value>::value, geometry::closure<Ring>::value > ring_area_type; template <typename Strategy> static inline void apply(Ring& r, Strategy const& strategy) { // Correct closure if necessary detail::correct_closure::close_or_open_ring<Ring>::apply(r); // Check area typedef typename area_result<Ring, Strategy>::type area_result_type; Predicate<area_result_type> predicate; area_result_type const zero = 0; if (predicate(ring_area_type::apply(r, // TEMP - in the future (umbrella) strategy will be passed geometry::strategies::area::services::strategy_converter < Strategy >::get(strategy)), zero)) { std::reverse(boost::begin(r), boost::end(r)); } } }; // Correct a polygon: normalizes all rings, sets outer ring clockwise, sets all // inner rings counter clockwise (or vice versa depending on orientation) template <typename Polygon> struct correct_polygon { typedef typename ring_type<Polygon>::type ring_type; template <typename Strategy> static inline void apply(Polygon& poly, Strategy const& strategy) { correct_ring < ring_type, std::less >::apply(exterior_ring(poly), strategy); typename interior_return_type<Polygon>::type rings = interior_rings(poly); for (typename detail::interior_iterator<Polygon>::type it = boost::begin(rings); it != boost::end(rings); ++it) { correct_ring < ring_type, std::greater >::apply(*it, strategy); } } }; }} // namespace detail::correct #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct correct: not_implemented<Tag> {}; template <typename Point> struct correct<Point, point_tag> : detail::correct::correct_nop<Point> {}; template <typename LineString> struct correct<LineString, linestring_tag> : detail::correct::correct_nop<LineString> {}; template <typename Segment> struct correct<Segment, segment_tag> : detail::correct::correct_nop<Segment> {}; template <typename Box> struct correct<Box, box_tag> : detail::correct::correct_box<Box> {}; template <typename Ring> struct correct<Ring, ring_tag> : detail::correct::correct_ring < Ring, std::less > {}; template <typename Polygon> struct correct<Polygon, polygon_tag> : detail::correct::correct_polygon<Polygon> {}; template <typename MultiPoint> struct correct<MultiPoint, multi_point_tag> : detail::correct::correct_nop<MultiPoint> {}; template <typename MultiLineString> struct correct<MultiLineString, multi_linestring_tag> : detail::correct::correct_nop<MultiLineString> {}; template <typename Geometry> struct correct<Geometry, multi_polygon_tag> : detail::multi_modify < Geometry, detail::correct::correct_polygon < typename boost::range_value<Geometry>::type > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct correct { template <typename Strategy> static inline void apply(Geometry& geometry, Strategy const& strategy) { concepts::check<Geometry const>(); dispatch::correct<Geometry>::apply(geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<void> { Strategy const& m_strategy; visitor(Strategy const& strategy): m_strategy(strategy) {} template <typename Geometry> void operator()(Geometry& geometry) const { correct<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy) { boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant /*! \brief Corrects a geometry \details Corrects a geometry: all rings which are wrongly oriented with respect to their expected orientation are reversed. To all rings which do not have a closing point and are typed as they should have one, the first point is appended. Also boxes can be corrected. \ingroup correct \tparam Geometry \tparam_geometry \param geometry \param_geometry which will be corrected if necessary \qbk{[include reference/algorithms/correct.qbk]} */ template <typename Geometry> inline void correct(Geometry& geometry) { typedef typename point_type<Geometry>::type point_type; typedef typename strategy::area::services::default_strategy < typename cs_tag<point_type>::type >::type strategy_type; resolve_variant::correct<Geometry>::apply(geometry, strategy_type()); } /*! \brief Corrects a geometry \details Corrects a geometry: all rings which are wrongly oriented with respect to their expected orientation are reversed. To all rings which do not have a closing point and are typed as they should have one, the first point is appended. Also boxes can be corrected. \ingroup correct \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Area} \param geometry \param_geometry which will be corrected if necessary \param strategy \param_strategy{area} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/correct.qbk]} */ template <typename Geometry, typename Strategy> inline void correct(Geometry& geometry, Strategy const& strategy) { resolve_variant::correct<Geometry>::apply(geometry, strategy); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP equals.hpp 0000644 00000002254 15125631656 0006564 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2015, 2016, 2017. // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP #define BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP #include <boost/geometry/algorithms/detail/equals/interface.hpp> #include <boost/geometry/algorithms/detail/equals/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP is_valid.hpp 0000644 00000001072 15125631656 0007061 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP #define BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP #include <boost/geometry/algorithms/detail/is_valid/interface.hpp> #include <boost/geometry/algorithms/detail/is_valid/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP area_result.hpp 0000644 00000010765 15125631656 0007606 0 ustar 00 // Boost.Geometry // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_STRATEGY_AREA_RESULT_HPP #define BOOST_GEOMETRY_STRATEGY_AREA_RESULT_HPP #include <type_traits> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/strategies/area/services.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> #include <boost/geometry/strategy/area.hpp> #include <boost/geometry/util/select_most_precise.hpp> #include <boost/geometry/util/sequence.hpp> #include <boost/geometry/util/type_traits.hpp> #include <boost/variant/variant_fwd.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace area { template < typename Geometry, typename Strategy, bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value > struct area_result { typedef decltype(std::declval<Strategy>().area(std::declval<Geometry>())) strategy_type; typedef typename strategy_type::template result_type<Geometry>::type type; }; template <typename Geometry, typename Strategy> struct area_result<Geometry, Strategy, false> { typedef typename Strategy::template result_type<Geometry>::type type; }; template < typename Geometry, bool IsGeometry = util::is_geometry<Geometry>::value > struct default_area_result : area_result < Geometry, typename geometry::strategies::area::services::default_strategy < Geometry >::type > {}; // Workaround for VS2015 #if defined(_MSC_VER) && (_MSC_VER < 1910) template < typename Geometry, bool IsGeometry = util::is_geometry<Geometry>::value > struct coordinate_type : geometry::coordinate_type<Geometry> {}; template <typename Geometry> struct coordinate_type<Geometry, false> { typedef int type; }; template <typename Geometry> struct default_area_result<Geometry, false> { typedef int type; }; #endif template <typename Curr, typename Next> struct more_precise_coordinate_type : std::is_same < typename coordinate_type<Curr>::type, typename geometry::select_most_precise < typename coordinate_type<Curr>::type, typename coordinate_type<Next>::type >::type > {}; template <typename Curr, typename Next> struct more_precise_default_area_result : std::is_same < typename default_area_result<Curr>::type, typename geometry::select_most_precise < typename default_area_result<Curr>::type, typename default_area_result<Next>::type >::type > {}; }} // namespace detail::area #endif //DOXYGEN_NO_DETAIL /*! \brief Meta-function defining return type of area function \ingroup area \note The return-type is defined by Geometry and Strategy */ template < typename Geometry, typename Strategy = default_strategy > struct area_result : detail::area::area_result<Geometry, Strategy> {}; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Strategy> struct area_result<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy> : geometry::area_result < typename util::select_pack_element < detail::area::more_precise_coordinate_type, BOOST_VARIANT_ENUM_PARAMS(T) >::type, Strategy > {}; template <typename Geometry> struct area_result<Geometry, default_strategy> : detail::area::default_area_result<Geometry> {}; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct area_result<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, default_strategy> : detail::area::default_area_result < typename util::select_pack_element < detail::area::more_precise_default_area_result, BOOST_VARIANT_ENUM_PARAMS(T) >::type > {}; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_STRATEGY_AREA_RESULT_HPP append.hpp 0000644 00000026471 15125631656 0006550 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP #define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/variant.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace append { template <typename Geometry, typename Point> struct append_no_action { static inline void apply(Geometry& , Point const& , int = 0, int = 0) { } }; template <typename Geometry, typename Point> struct append_point { static inline void apply(Geometry& geometry, Point const& point, int = 0, int = 0) { typename geometry::point_type<Geometry>::type copy; geometry::detail::conversion::convert_point_to_point(point, copy); traits::push_back<Geometry>::apply(geometry, copy); } }; template <typename Geometry, typename Range> struct append_range { typedef typename boost::range_value<Range>::type point_type; static inline void apply(Geometry& geometry, Range const& range, int = 0, int = 0) { for (typename boost::range_iterator<Range const>::type it = boost::begin(range); it != boost::end(range); ++it) { append_point<Geometry, point_type>::apply(geometry, *it); } } }; template <typename Polygon, typename Point> struct point_to_polygon { typedef typename ring_type<Polygon>::type ring_type; typedef typename ring_return_type<Polygon>::type exterior_ring_type; typedef typename interior_return_type<Polygon>::type interior_ring_range_type; static inline void apply(Polygon& polygon, Point const& point, int ring_index, int = 0) { if (ring_index == -1) { exterior_ring_type ext_ring = exterior_ring(polygon); append_point<ring_type, Point>::apply( ext_ring, point); } else if (ring_index < int(num_interior_rings(polygon))) { interior_ring_range_type int_rings = interior_rings(polygon); append_point<ring_type, Point>::apply( range::at(int_rings, ring_index), point); } } }; template <typename Polygon, typename Range> struct range_to_polygon { typedef typename ring_type<Polygon>::type ring_type; typedef typename ring_return_type<Polygon>::type exterior_ring_type; typedef typename interior_return_type<Polygon>::type interior_ring_range_type; static inline void apply(Polygon& polygon, Range const& range, int ring_index, int = 0) { if (ring_index == -1) { exterior_ring_type ext_ring = exterior_ring(polygon); append_range<ring_type, Range>::apply( ext_ring, range); } else if (ring_index < int(num_interior_rings(polygon))) { interior_ring_range_type int_rings = interior_rings(polygon); append_range<ring_type, Range>::apply( range::at(int_rings, ring_index), range); } } }; }} // namespace detail::append #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { namespace splitted_dispatch { template <typename Tag, typename Geometry, typename Point> struct append_point : detail::append::append_no_action<Geometry, Point> {}; template <typename Geometry, typename Point> struct append_point<linestring_tag, Geometry, Point> : detail::append::append_point<Geometry, Point> {}; template <typename Geometry, typename Point> struct append_point<ring_tag, Geometry, Point> : detail::append::append_point<Geometry, Point> {}; template <typename Polygon, typename Point> struct append_point<polygon_tag, Polygon, Point> : detail::append::point_to_polygon<Polygon, Point> {}; template <typename Tag, typename Geometry, typename Range> struct append_range : detail::append::append_no_action<Geometry, Range> {}; template <typename Geometry, typename Range> struct append_range<linestring_tag, Geometry, Range> : detail::append::append_range<Geometry, Range> {}; template <typename Geometry, typename Range> struct append_range<ring_tag, Geometry, Range> : detail::append::append_range<Geometry, Range> {}; template <typename Polygon, typename Range> struct append_range<polygon_tag, Polygon, Range> : detail::append::range_to_polygon<Polygon, Range> {}; } // namespace splitted_dispatch // Default: append a range (or linestring or ring or whatever) to any geometry template < typename Geometry, typename RangeOrPoint, typename TagRangeOrPoint = typename tag<RangeOrPoint>::type > struct append : splitted_dispatch::append_range<typename tag<Geometry>::type, Geometry, RangeOrPoint> {}; // Specialization for point to append a point to any geometry template <typename Geometry, typename RangeOrPoint> struct append<Geometry, RangeOrPoint, point_tag> : splitted_dispatch::append_point<typename tag<Geometry>::type, Geometry, RangeOrPoint> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace append { template <typename MultiGeometry, typename RangeOrPoint> struct append_to_multigeometry { static inline void apply(MultiGeometry& multigeometry, RangeOrPoint const& range_or_point, int ring_index, int multi_index) { dispatch::append < typename boost::range_value<MultiGeometry>::type, RangeOrPoint >::apply(range::at(multigeometry, multi_index), range_or_point, ring_index); } }; }} // namespace detail::append #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { namespace splitted_dispatch { template <typename Geometry, typename Point> struct append_point<multi_point_tag, Geometry, Point> : detail::append::append_point<Geometry, Point> {}; template <typename Geometry, typename Range> struct append_range<multi_point_tag, Geometry, Range> : detail::append::append_range<Geometry, Range> {}; template <typename MultiGeometry, typename RangeOrPoint> struct append_point<multi_linestring_tag, MultiGeometry, RangeOrPoint> : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> {}; template <typename MultiGeometry, typename RangeOrPoint> struct append_range<multi_linestring_tag, MultiGeometry, RangeOrPoint> : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> {}; template <typename MultiGeometry, typename RangeOrPoint> struct append_point<multi_polygon_tag, MultiGeometry, RangeOrPoint> : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> {}; template <typename MultiGeometry, typename RangeOrPoint> struct append_range<multi_polygon_tag, MultiGeometry, RangeOrPoint> : detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint> {}; } // namespace splitted_dispatch } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct append { template <typename RangeOrPoint> static inline void apply(Geometry& geometry, RangeOrPoint const& range_or_point, int ring_index, int multi_index) { concepts::check<Geometry>(); dispatch::append<Geometry, RangeOrPoint>::apply(geometry, range_or_point, ring_index, multi_index); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct append<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename RangeOrPoint> struct visitor: boost::static_visitor<void> { RangeOrPoint const& m_range_or_point; int m_ring_index; int m_multi_index; visitor(RangeOrPoint const& range_or_point, int ring_index, int multi_index): m_range_or_point(range_or_point), m_ring_index(ring_index), m_multi_index(multi_index) {} template <typename Geometry> void operator()(Geometry& geometry) const { append<Geometry>::apply(geometry, m_range_or_point, m_ring_index, m_multi_index); } }; template <typename RangeOrPoint> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant_geometry, RangeOrPoint const& range_or_point, int ring_index, int multi_index) { boost::apply_visitor( visitor<RangeOrPoint>( range_or_point, ring_index, multi_index ), variant_geometry ); } }; } // namespace resolve_variant; /*! \brief Appends one or more points to a linestring, ring, polygon, multi-geometry \ingroup append \tparam Geometry \tparam_geometry \tparam RangeOrPoint Either a range or a point, fullfilling Boost.Range concept or Boost.Geometry Point Concept \param geometry \param_geometry \param range_or_point The point or range to add \param ring_index The index of the ring in case of a polygon: exterior ring (-1, the default) or interior ring index \param multi_index The index of the geometry to which the points are appended \qbk{[include reference/algorithms/append.qbk]} } */ template <typename Geometry, typename RangeOrPoint> inline void append(Geometry& geometry, RangeOrPoint const& range_or_point, int ring_index = -1, int multi_index = 0) { resolve_variant::append<Geometry> ::apply(geometry, range_or_point, ring_index, multi_index); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP relation.hpp 0000644 00000001214 15125631656 0007102 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_RELATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_RELATION_HPP #include <boost/geometry/algorithms/detail/relation/interface.hpp> #include <boost/geometry/algorithms/detail/relation/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_RELATION_HPP covered_by.hpp 0000644 00000002065 15125631656 0007413 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013, 2014, 2017. // Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP #define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP #include <boost/geometry/algorithms/detail/covered_by/interface.hpp> #include <boost/geometry/algorithms/detail/covered_by/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP distance.hpp 0000644 00000002126 15125631656 0007062 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP #include <boost/geometry/algorithms/detail/distance/interface.hpp> #include <boost/geometry/algorithms/detail/distance/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DISTANCE_HPP intersection.hpp 0000644 00000001446 15125631656 0010002 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP #include <boost/geometry/algorithms/detail/intersection/interface.hpp> #include <boost/geometry/algorithms/detail/intersection/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTION_HPP num_geometries.hpp 0000644 00000007127 15125631656 0010320 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_NUM_GEOMETRIES_HPP #define BOOST_GEOMETRY_ALGORITHMS_NUM_GEOMETRIES_HPP #include <cstddef> #include <boost/range/size.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/counting.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag_cast < typename tag<Geometry>::type, single_tag, multi_tag >::type > struct num_geometries: not_implemented<Tag> {}; template <typename Geometry> struct num_geometries<Geometry, single_tag> : detail::counting::other_count<1> {}; template <typename MultiGeometry> struct num_geometries<MultiGeometry, multi_tag> { static inline std::size_t apply(MultiGeometry const& multi_geometry) { return boost::size(multi_geometry); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct num_geometries { static inline std::size_t apply(Geometry const& geometry) { concepts::check<Geometry const>(); return dispatch::num_geometries<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct num_geometries<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<std::size_t> { template <typename Geometry> inline std::size_t operator()(Geometry const& geometry) const { return num_geometries<Geometry>::apply(geometry); } }; static inline std::size_t apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) { return boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{number of geometries} \ingroup num_geometries \details \details_calc{num_geometries, number of geometries}. \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{number of geometries} \qbk{[include reference/algorithms/num_geometries.qbk]} */ template <typename Geometry> inline std::size_t num_geometries(Geometry const& geometry) { return resolve_variant::num_geometries<Geometry>::apply(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_NUM_GEOMETRIES_HPP transform.hpp 0000644 00000034036 15125631656 0007310 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP #define BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP #include <cmath> #include <iterator> #include <type_traits> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/transform.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace transform { struct transform_point { template <typename Point1, typename Point2, typename Strategy> static inline bool apply(Point1 const& p1, Point2& p2, Strategy const& strategy) { return strategy.apply(p1, p2); } }; struct transform_box { template <typename Box1, typename Box2, typename Strategy> static inline bool apply(Box1 const& b1, Box2& b2, Strategy const& strategy) { typedef typename point_type<Box1>::type point_type1; typedef typename point_type<Box2>::type point_type2; point_type1 lower_left, upper_right; geometry::detail::assign::assign_box_2d_corner<min_corner, min_corner>( b1, lower_left); geometry::detail::assign::assign_box_2d_corner<max_corner, max_corner>( b1, upper_right); point_type2 p1, p2; if (strategy.apply(lower_left, p1) && strategy.apply(upper_right, p2)) { // Create a valid box and therefore swap if necessary typedef typename coordinate_type<point_type2>::type coordinate_type; coordinate_type x1 = geometry::get<0>(p1) , y1 = geometry::get<1>(p1) , x2 = geometry::get<0>(p2) , y2 = geometry::get<1>(p2); if (x1 > x2) { std::swap(x1, x2); } if (y1 > y2) { std::swap(y1, y2); } geometry::set<min_corner, 0>(b2, x1); geometry::set<min_corner, 1>(b2, y1); geometry::set<max_corner, 0>(b2, x2); geometry::set<max_corner, 1>(b2, y2); return true; } return false; } }; struct transform_box_or_segment { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& source, Geometry2& target, Strategy const& strategy) { typedef typename point_type<Geometry1>::type point_type1; typedef typename point_type<Geometry2>::type point_type2; point_type1 source_point[2]; geometry::detail::assign_point_from_index<0>(source, source_point[0]); geometry::detail::assign_point_from_index<1>(source, source_point[1]); point_type2 target_point[2]; if (strategy.apply(source_point[0], target_point[0]) && strategy.apply(source_point[1], target_point[1])) { geometry::detail::assign_point_to_index<0>(target_point[0], target); geometry::detail::assign_point_to_index<1>(target_point[1], target); return true; } return false; } }; template < typename PointOut, typename OutputIterator, typename Range, typename Strategy > inline bool transform_range_out(Range const& range, OutputIterator out, Strategy const& strategy) { PointOut point_out; for(typename boost::range_iterator<Range const>::type it = boost::begin(range); it != boost::end(range); ++it) { if (! transform_point::apply(*it, point_out, strategy)) { return false; } *out++ = point_out; } return true; } struct transform_polygon { template <typename Polygon1, typename Polygon2, typename Strategy> static inline bool apply(Polygon1 const& poly1, Polygon2& poly2, Strategy const& strategy) { typedef typename point_type<Polygon2>::type point2_type; geometry::clear(poly2); if (!transform_range_out<point2_type>(geometry::exterior_ring(poly1), range::back_inserter(geometry::exterior_ring(poly2)), strategy)) { return false; } // Note: here a resizeable container is assumed. traits::resize < typename std::remove_reference < typename traits::interior_mutable_type<Polygon2>::type >::type >::apply(geometry::interior_rings(poly2), geometry::num_interior_rings(poly1)); typename geometry::interior_return_type<Polygon1 const>::type rings1 = geometry::interior_rings(poly1); typename geometry::interior_return_type<Polygon2>::type rings2 = geometry::interior_rings(poly2); typename detail::interior_iterator<Polygon1 const>::type it1 = boost::begin(rings1); typename detail::interior_iterator<Polygon2>::type it2 = boost::begin(rings2); for ( ; it1 != boost::end(rings1); ++it1, ++it2) { if ( ! transform_range_out<point2_type>(*it1, range::back_inserter(*it2), strategy) ) { return false; } } return true; } }; template <typename Point1, typename Point2> struct select_strategy { typedef typename strategy::transform::services::default_strategy < typename cs_tag<Point1>::type, typename cs_tag<Point2>::type, typename coordinate_system<Point1>::type, typename coordinate_system<Point2>::type, dimension<Point1>::type::value, dimension<Point2>::type::value, typename point_type<Point1>::type, typename point_type<Point2>::type >::type type; }; struct transform_range { template <typename Range1, typename Range2, typename Strategy> static inline bool apply(Range1 const& range1, Range2& range2, Strategy const& strategy) { typedef typename point_type<Range2>::type point_type; // Should NOT be done here! // geometry::clear(range2); return transform_range_out<point_type>(range1, range::back_inserter(range2), strategy); } }; /*! \brief Is able to transform any multi-geometry, calling the single-version as policy */ template <typename Policy> struct transform_multi { template <typename Multi1, typename Multi2, typename S> static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy) { traits::resize<Multi2>::apply(multi2, boost::size(multi1)); typename boost::range_iterator<Multi1 const>::type it1 = boost::begin(multi1); typename boost::range_iterator<Multi2>::type it2 = boost::begin(multi2); for (; it1 != boost::end(multi1); ++it1, ++it2) { if (! Policy::apply(*it1, *it2, strategy)) { return false; } } return true; } }; }} // namespace detail::transform #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type, typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type > struct transform {}; template <typename Point1, typename Point2> struct transform<Point1, Point2, point_tag, point_tag> : detail::transform::transform_point { }; template <typename Linestring1, typename Linestring2> struct transform < Linestring1, Linestring2, linestring_tag, linestring_tag > : detail::transform::transform_range { }; template <typename Range1, typename Range2> struct transform<Range1, Range2, ring_tag, ring_tag> : detail::transform::transform_range { }; template <typename Polygon1, typename Polygon2> struct transform<Polygon1, Polygon2, polygon_tag, polygon_tag> : detail::transform::transform_polygon { }; template <typename Box1, typename Box2> struct transform<Box1, Box2, box_tag, box_tag> : detail::transform::transform_box { }; template <typename Segment1, typename Segment2> struct transform<Segment1, Segment2, segment_tag, segment_tag> : detail::transform::transform_box_or_segment { }; template <typename Multi1, typename Multi2> struct transform < Multi1, Multi2, multi_tag, multi_tag > : detail::transform::transform_multi < dispatch::transform < typename boost::range_value<Multi1>::type, typename boost::range_value<Multi2>::type > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct transform { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2>(); return dispatch::transform<Geometry1, Geometry2>::apply( geometry1, geometry2, strategy ); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2& geometry2, default_strategy) { return apply( geometry1, geometry2, typename detail::transform::select_strategy<Geometry1, Geometry2>::type() ); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct transform { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2& geometry2, Strategy const& strategy) { return resolve_strategy::transform::apply( geometry1, geometry2, strategy ); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct transform<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: static_visitor<bool> { Geometry2& m_geometry2; Strategy const& m_strategy; visitor(Geometry2& geometry2, Strategy const& strategy) : m_geometry2(geometry2) , m_strategy(strategy) {} template <typename Geometry1> inline bool operator()(Geometry1 const& geometry1) const { return transform<Geometry1, Geometry2>::apply( geometry1, m_geometry2, m_strategy ); } }; template <typename Strategy> static inline bool apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2& geometry2, Strategy const& strategy ) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; } // namespace resolve_variant /*! \brief Transforms from one geometry to another geometry \brief_strategy \ingroup transform \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy strategy \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy The strategy to be used for transformation \return True if the transformation could be done \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/transform_with_strategy.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2, Strategy const& strategy) { return resolve_variant::transform<Geometry1, Geometry2> ::apply(geometry1, geometry2, strategy); } /*! \brief Transforms from one geometry to another geometry using a strategy \ingroup transform \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return True if the transformation could be done \qbk{[include reference/algorithms/transform.qbk]} */ template <typename Geometry1, typename Geometry2> inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2) { return geometry::transform(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP expand.hpp 0000644 00000002061 15125631656 0006545 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015. // Modifications copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_EXPAND_HPP #define BOOST_GEOMETRY_ALGORITHMS_EXPAND_HPP #include <boost/geometry/algorithms/detail/expand/interface.hpp> #include <boost/geometry/algorithms/detail/expand/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_EXPAND_HPP perimeter.hpp 0000644 00000016171 15125631656 0007271 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP #define BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/length.hpp> #include <boost/geometry/algorithms/detail/calculate_null.hpp> #include <boost/geometry/algorithms/detail/calculate_sum.hpp> #include <boost/geometry/algorithms/detail/multi_sum.hpp> // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_length_result.hpp> #include <boost/geometry/strategies/default_strategy.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Default perimeter is 0.0, specializations implement calculated values template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct perimeter : detail::calculate_null { typedef typename default_length_result<Geometry>::type return_type; template <typename Strategy> static inline return_type apply(Geometry const& geometry, Strategy const& strategy) { return calculate_null::apply<return_type>(geometry, strategy); } }; template <typename Geometry> struct perimeter<Geometry, ring_tag> : detail::length::range_length < Geometry, closure<Geometry>::value > {}; template <typename Polygon> struct perimeter<Polygon, polygon_tag> : detail::calculate_polygon_sum { typedef typename default_length_result<Polygon>::type return_type; typedef detail::length::range_length < typename ring_type<Polygon>::type, closure<Polygon>::value > policy; template <typename Strategy> static inline return_type apply(Polygon const& polygon, Strategy const& strategy) { return calculate_polygon_sum::apply<return_type, policy>(polygon, strategy); } }; template <typename MultiPolygon> struct perimeter<MultiPolygon, multi_polygon_tag> : detail::multi_sum { typedef typename default_length_result<MultiPolygon>::type return_type; template <typename Strategy> static inline return_type apply(MultiPolygon const& multi, Strategy const& strategy) { return multi_sum::apply < return_type, perimeter<typename boost::range_value<MultiPolygon>::type> >(multi, strategy); } }; // box,n-sphere: to be implemented } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct perimeter { template <typename Geometry, typename Strategy> static inline typename default_length_result<Geometry>::type apply(Geometry const& geometry, Strategy const& strategy) { return dispatch::perimeter<Geometry>::apply(geometry, strategy); } template <typename Geometry> static inline typename default_length_result<Geometry>::type apply(Geometry const& geometry, default_strategy) { typedef typename strategy::distance::services::default_strategy < point_tag, point_tag, typename point_type<Geometry>::type >::type strategy_type; return dispatch::perimeter<Geometry>::apply(geometry, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct perimeter { template <typename Strategy> static inline typename default_length_result<Geometry>::type apply(Geometry const& geometry, Strategy const& strategy) { concepts::check<Geometry const>(); return resolve_strategy::perimeter::apply(geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct perimeter<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { typedef typename default_length_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >::type result_type; template <typename Strategy> struct visitor: boost::static_visitor<result_type> { Strategy const& m_strategy; visitor(Strategy const& strategy): m_strategy(strategy) {} template <typename Geometry> typename default_length_result<Geometry>::type operator()(Geometry const& geometry) const { return perimeter<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline result_type apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{perimeter} \ingroup perimeter \details The function perimeter returns the perimeter of a geometry, using the default distance-calculation-strategy \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{perimeter} \qbk{[include reference/algorithms/perimeter.qbk]} \qbk{ [heading Example] [perimeter] [perimeter_output] } */ template<typename Geometry> inline typename default_length_result<Geometry>::type perimeter( Geometry const& geometry) { // detail::throw_on_empty_input(geometry); return resolve_variant::perimeter<Geometry>::apply(geometry, default_strategy()); } /*! \brief \brief_calc{perimeter} \brief_strategy \ingroup perimeter \details The function perimeter returns the perimeter of a geometry, using specified strategy \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{distance} \param geometry \param_geometry \param strategy strategy to be used for distance calculations. \return \return_calc{perimeter} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/perimeter.qbk]} */ template<typename Geometry, typename Strategy> inline typename default_length_result<Geometry>::type perimeter( Geometry const& geometry, Strategy const& strategy) { // detail::throw_on_empty_input(geometry); return resolve_variant::perimeter<Geometry>::apply(geometry, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_PERIMETER_HPP convex_hull.hpp 0000644 00000026505 15125631656 0007625 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014, 2015. // Modifications copyright (c) 2014-2015 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP #define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP #include <boost/array.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/convex_hull.hpp> #include <boost/geometry/strategies/concepts/convex_hull_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/views/detail/range_type.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/detail/as_range.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace convex_hull { template <order_selector Order, closure_selector Closure> struct hull_insert { // Member template function (to avoid inconvenient declaration // of output-iterator-type, from hull_to_geometry) template <typename Geometry, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry const& geometry, OutputIterator out, Strategy const& strategy) { typename Strategy::state_type state; strategy.apply(geometry, state); strategy.result(state, out, Order == clockwise, Closure != open); return out; } }; struct hull_to_geometry { template <typename Geometry, typename OutputGeometry, typename Strategy> static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { hull_insert < geometry::point_order<OutputGeometry>::value, geometry::closure<OutputGeometry>::value >::apply(geometry, range::back_inserter( // Handle linestring, ring and polygon the same: detail::as_range < typename range_type<OutputGeometry>::type >(out)), strategy); } }; }} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct convex_hull : detail::convex_hull::hull_to_geometry {}; template <typename Box> struct convex_hull<Box, box_tag> { template <typename OutputGeometry, typename Strategy> static inline void apply(Box const& box, OutputGeometry& out, Strategy const& ) { static bool const Close = geometry::closure<OutputGeometry>::value == closed; static bool const Reverse = geometry::point_order<OutputGeometry>::value == counterclockwise; // A hull for boxes is trivial. Any strategy is (currently) skipped. boost::array<typename point_type<Box>::type, 4> range; geometry::detail::assign_box_corners_oriented<Reverse>(box, range); geometry::append(out, range); if (BOOST_GEOMETRY_CONDITION(Close)) { geometry::append(out, *boost::begin(range)); } } }; template <order_selector Order, closure_selector Closure> struct convex_hull_insert : detail::convex_hull::hull_insert<Order, Closure> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct convex_hull { template <typename Geometry, typename OutputGeometry, typename Strategy> static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy<Strategy>) ); dispatch::convex_hull<Geometry>::apply(geometry, out, strategy); } template <typename Geometry, typename OutputGeometry> static inline void apply(Geometry const& geometry, OutputGeometry& out, default_strategy) { typedef typename strategy_convex_hull< Geometry, typename point_type<Geometry>::type >::type strategy_type; apply(geometry, out, strategy_type()); } }; struct convex_hull_insert { template <typename Geometry, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy) { BOOST_CONCEPT_ASSERT( (geometry::concepts::ConvexHullStrategy<Strategy>) ); return dispatch::convex_hull_insert< geometry::point_order<Geometry>::value, geometry::closure<Geometry>::value >::apply(geometry, out, strategy); } template <typename Geometry, typename OutputIterator> static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, default_strategy) { typedef typename strategy_convex_hull< Geometry, typename point_type<Geometry>::type >::type strategy_type; return apply(geometry, out, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct convex_hull { template <typename OutputGeometry, typename Strategy> static inline void apply(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions< const Geometry, OutputGeometry >(); resolve_strategy::convex_hull::apply(geometry, out, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct convex_hull<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename OutputGeometry, typename Strategy> struct visitor: boost::static_visitor<void> { OutputGeometry& m_out; Strategy const& m_strategy; visitor(OutputGeometry& out, Strategy const& strategy) : m_out(out), m_strategy(strategy) {} template <typename Geometry> void operator()(Geometry const& geometry) const { convex_hull<Geometry>::apply(geometry, m_out, m_strategy); } }; template <typename OutputGeometry, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, OutputGeometry& out, Strategy const& strategy) { boost::apply_visitor(visitor<OutputGeometry, Strategy>(out, strategy), geometry); } }; template <typename Geometry> struct convex_hull_insert { template <typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry const& geometry, OutputIterator& out, Strategy const& strategy) { // Concept: output point type = point type of input geometry concepts::check<Geometry const>(); concepts::check<typename point_type<Geometry>::type>(); return resolve_strategy::convex_hull_insert::apply(geometry, out, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct convex_hull_insert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename OutputIterator, typename Strategy> struct visitor: boost::static_visitor<OutputIterator> { OutputIterator& m_out; Strategy const& m_strategy; visitor(OutputIterator& out, Strategy const& strategy) : m_out(out), m_strategy(strategy) {} template <typename Geometry> OutputIterator operator()(Geometry const& geometry) const { return convex_hull_insert<Geometry>::apply(geometry, m_out, m_strategy); } }; template <typename OutputIterator, typename Strategy> static inline OutputIterator apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, OutputIterator& out, Strategy const& strategy) { return boost::apply_visitor(visitor<OutputIterator, Strategy>(out, strategy), geometry); } }; } // namespace resolve_variant template<typename Geometry, typename OutputGeometry, typename Strategy> inline void convex_hull(Geometry const& geometry, OutputGeometry& out, Strategy const& strategy) { if (geometry::is_empty(geometry)) { // Leave output empty return; } resolve_variant::convex_hull<Geometry>::apply(geometry, out, strategy); } /*! \brief \brief_calc{convex hull} \ingroup convex_hull \details \details_calc{convex_hull,convex hull}. \tparam Geometry the input geometry type \tparam OutputGeometry the output geometry type \param geometry \param_geometry, input geometry \param hull \param_geometry \param_set{convex hull} \qbk{[include reference/algorithms/convex_hull.qbk]} */ template<typename Geometry, typename OutputGeometry> inline void convex_hull(Geometry const& geometry, OutputGeometry& hull) { geometry::convex_hull(geometry, hull, default_strategy()); } #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace convex_hull { template<typename Geometry, typename OutputIterator, typename Strategy> inline OutputIterator convex_hull_insert(Geometry const& geometry, OutputIterator out, Strategy const& strategy) { return resolve_variant::convex_hull_insert<Geometry> ::apply(geometry, out, strategy); } /*! \brief Calculate the convex hull of a geometry, output-iterator version \ingroup convex_hull \tparam Geometry the input geometry type \tparam OutputIterator: an output-iterator \param geometry the geometry to calculate convex hull from \param out an output iterator outputing points of the convex hull \note This overloaded version outputs to an output iterator. In this case, nothing is known about its point-type or about its clockwise order. Therefore, the input point-type and order are copied */ template<typename Geometry, typename OutputIterator> inline OutputIterator convex_hull_insert(Geometry const& geometry, OutputIterator out) { return convex_hull_insert(geometry, out, default_strategy()); } }} // namespace detail::convex_hull #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP num_segments.hpp 0000644 00000011336 15125631656 0007777 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_NUM_SEGMENTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP #include <cstddef> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/counting.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace num_segments { struct range_count { template <typename Range> static inline std::size_t apply(Range const& range) { std::size_t n = boost::size(range); if ( n <= 1 ) { return 0; } return geometry::closure<Range>::value == open ? n : static_cast<std::size_t>(n - 1); } }; }} // namespace detail::num_segments #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct num_segments : not_implemented<Tag> {}; template <typename Geometry> struct num_segments<Geometry, point_tag> : detail::counting::other_count<0> {}; // the number of segments (1-dimensional faces) of the hypercube is // given by the formula: d * 2^(d-1), where d is the dimension of the // hypercube; see also: // http://en.wikipedia.org/wiki/Hypercube template <typename Geometry> struct num_segments<Geometry, box_tag> : detail::counting::other_count < geometry::dimension<Geometry>::value * (1 << (geometry::dimension<Geometry>::value - 1)) > {}; template <typename Geometry> struct num_segments<Geometry, segment_tag> : detail::counting::other_count<1> {}; template <typename Geometry> struct num_segments<Geometry, linestring_tag> : detail::num_segments::range_count {}; template <typename Geometry> struct num_segments<Geometry, ring_tag> : detail::num_segments::range_count {}; template <typename Geometry> struct num_segments<Geometry, polygon_tag> : detail::counting::polygon_count<detail::num_segments::range_count> {}; template <typename Geometry> struct num_segments<Geometry, multi_point_tag> : detail::counting::other_count<0> {}; template <typename Geometry> struct num_segments<Geometry, multi_linestring_tag> : detail::counting::multi_count < num_segments< typename boost::range_value<Geometry>::type> > {}; template <typename Geometry> struct num_segments<Geometry, multi_polygon_tag> : detail::counting::multi_count < num_segments< typename boost::range_value<Geometry>::type> > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct num_segments { static inline std::size_t apply(Geometry const& geometry) { concepts::check<Geometry const>(); return dispatch::num_segments<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct num_segments<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<std::size_t> { template <typename Geometry> inline std::size_t operator()(Geometry const& geometry) const { return num_segments<Geometry>::apply(geometry); } }; static inline std::size_t apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) { return boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{number of segments} \ingroup num_segments \details \details_calc{num_segments, number of segments}. \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{number of segments} \qbk{[include reference/algorithms/num_segments.qbk]} */ template <typename Geometry> inline std::size_t num_segments(Geometry const& geometry) { return resolve_variant::num_segments<Geometry>::apply(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_NUM_SEGMENTS_HPP line_interpolate.hpp 0000644 00000031464 15125631656 0010634 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2018-2020 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP #define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP #include <iterator> #include <type_traits> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/iterator.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/length.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/line_interpolate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace line_interpolate { struct convert_and_push_back { template <typename Range, typename Point> inline void apply(Point const& p, Range& range) { typename boost::range_value<Range>::type p2; geometry::detail::conversion::convert_point_to_point(p, p2); range::push_back(range, p2); } }; struct convert_and_assign { template <typename Point1, typename Point2> inline void apply(Point1 const& p1, Point2& p2) { geometry::detail::conversion::convert_point_to_point(p1, p2); } }; /*! \brief Internal, calculates interpolation point of a linestring using iterator pairs and specified strategy */ template <typename Policy> struct interpolate_range { template < typename Range, typename Distance, typename PointLike, typename Strategy > static inline void apply(Range const& range, Distance const& max_distance, PointLike & pointlike, Strategy const& strategy) { Policy policy; typedef typename boost::range_iterator<Range const>::type iterator_t; typedef typename boost::range_value<Range const>::type point_t; iterator_t it = boost::begin(range); iterator_t end = boost::end(range); if (it == end) // empty(range) { BOOST_THROW_EXCEPTION(empty_input_exception()); return; } if (max_distance <= 0) //non positive distance { policy.apply(*it, pointlike); return; } iterator_t prev = it++; Distance repeated_distance = max_distance; Distance prev_distance = 0; Distance current_distance = 0; point_t start_p = *prev; for ( ; it != end ; ++it) { Distance dist = strategy.get_distance_pp_strategy().apply(*prev, *it); current_distance = prev_distance + dist; while (current_distance >= repeated_distance) { point_t p; Distance diff_distance = current_distance - prev_distance; BOOST_ASSERT(diff_distance != Distance(0)); strategy.apply(start_p, *it, (repeated_distance - prev_distance)/diff_distance, p, diff_distance); policy.apply(p, pointlike); if (std::is_same<PointLike, point_t>::value) { return; } start_p = p; prev_distance = repeated_distance; repeated_distance += max_distance; } prev_distance = current_distance; prev = it; start_p = *prev; } // case when max_distance is larger than linestring's length // return the last point in range (range is not empty) if (repeated_distance == max_distance) { policy.apply(*(end-1), pointlike); } } }; template <typename Policy> struct interpolate_segment { template <typename Segment, typename Distance, typename Pointlike, typename Strategy> static inline void apply(Segment const& segment, Distance const& max_distance, Pointlike & point, Strategy const& strategy) { interpolate_range<Policy>().apply(segment_view<Segment>(segment), max_distance, point, strategy); } }; }} // namespace detail::line_interpolate #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Pointlike, typename Tag1 = typename tag<Geometry>::type, typename Tag2 = typename tag<Pointlike>::type > struct line_interpolate { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not implemented for this Geometry type.", Geometry, Pointlike); }; template <typename Geometry, typename Pointlike> struct line_interpolate<Geometry, Pointlike, linestring_tag, point_tag> : detail::line_interpolate::interpolate_range < detail::line_interpolate::convert_and_assign > {}; template <typename Geometry, typename Pointlike> struct line_interpolate<Geometry, Pointlike, linestring_tag, multi_point_tag> : detail::line_interpolate::interpolate_range < detail::line_interpolate::convert_and_push_back > {}; template <typename Geometry, typename Pointlike> struct line_interpolate<Geometry, Pointlike, segment_tag, point_tag> : detail::line_interpolate::interpolate_segment < detail::line_interpolate::convert_and_assign > {}; template <typename Geometry, typename Pointlike> struct line_interpolate<Geometry, Pointlike, segment_tag, multi_point_tag> : detail::line_interpolate::interpolate_segment < detail::line_interpolate::convert_and_push_back > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct line_interpolate { template < typename Geometry, typename Distance, typename Pointlike, typename Strategy > static inline void apply(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, Strategy const& strategy) { dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry, max_distance, pointlike, strategy); } template <typename Geometry, typename Distance, typename Pointlike> static inline void apply(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, default_strategy) { typedef typename strategy::line_interpolate::services::default_strategy < typename cs_tag<Geometry>::type >::type strategy_type; dispatch::line_interpolate<Geometry, Pointlike>::apply(geometry, max_distance, pointlike, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct line_interpolate { template <typename Distance, typename Pointlike, typename Strategy> static inline void apply(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, Strategy const& strategy) { return resolve_strategy::line_interpolate::apply(geometry, max_distance, pointlike, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct line_interpolate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Pointlike, typename Strategy> struct visitor: boost::static_visitor<void> { Pointlike const& m_pointlike; Strategy const& m_strategy; visitor(Pointlike const& pointlike, Strategy const& strategy) : m_pointlike(pointlike) , m_strategy(strategy) {} template <typename Geometry, typename Distance> void operator()(Geometry const& geometry, Distance const& max_distance) const { line_interpolate<Geometry>::apply(geometry, max_distance, m_pointlike, m_strategy); } }; template <typename Distance, typename Pointlike, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, double const& max_distance, Pointlike & pointlike, Strategy const& strategy) { boost::apply_visitor( visitor<Pointlike, Strategy>(pointlike, strategy), geometry, max_distance ); } }; } // namespace resolve_variant /*! \brief Returns one or more points interpolated along a LineString \brief_strategy \ingroup line_interpolate \tparam Geometry Any type fulfilling a LineString concept \tparam Distance A numerical distance measure \tparam Pointlike Any type fulfilling Point or Multipoint concept \tparam Strategy A type fulfilling a LineInterpolatePointStrategy concept \param geometry Input geometry \param max_distance Distance threshold (in units depending on coordinate system) representing the spacing between the points \param pointlike Output: either a Point (exactly one point will be constructed) or a MultiPoint (depending on the max_distance one or more points will be constructed) \param strategy line_interpolate strategy to be used for interpolation of points \qbk{[include reference/algorithms/line_interpolate.qbk]} \qbk{distinguish,with strategy} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_line_interpolate_cartesian Cartesian] \* [link geometry.reference.strategies.strategy_line_interpolate_spherical Spherical] \* [link geometry.reference.strategies.strategy_line_interpolate_geographic Geographic] [heading Example] [line_interpolate_strategy] [line_interpolate_strategy_output] [heading See also] \* [link geometry.reference.algorithms.densify densify] } */ template < typename Geometry, typename Distance, typename Pointlike, typename Strategy > inline void line_interpolate(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike, Strategy const& strategy) { concepts::check<Geometry const>(); // detail::throw_on_empty_input(geometry); return resolve_variant::line_interpolate<Geometry> ::apply(geometry, max_distance, pointlike, strategy); } /*! \brief Returns one or more points interpolated along a LineString. \ingroup line_interpolate \tparam Geometry Any type fulfilling a LineString concept \tparam Distance A numerical distance measure \tparam Pointlike Any type fulfilling Point or Multipoint concept \param geometry Input geometry \param max_distance Distance threshold (in units depending on coordinate system) representing the spacing between the points \param pointlike Output: either a Point (exactly one point will be constructed) or a MultiPoint (depending on the max_distance one or more points will be constructed) \qbk{[include reference/algorithms/line_interpolate.qbk] [heading Example] [line_interpolate] [line_interpolate_output] [heading See also] \* [link geometry.reference.algorithms.densify densify] } */ template<typename Geometry, typename Distance, typename Pointlike> inline void line_interpolate(Geometry const& geometry, Distance const& max_distance, Pointlike & pointlike) { concepts::check<Geometry const>(); // detail::throw_on_empty_input(geometry); return resolve_variant::line_interpolate<Geometry> ::apply(geometry, max_distance, pointlike, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP sym_difference.hpp 0000644 00000055201 15125631656 0010254 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015, 2017, 2019, 2020. // Modifications copyright (c) 2015-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP #include <algorithm> #include <iterator> #include <vector> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/intersection.hpp> #include <boost/geometry/algorithms/union.hpp> #include <boost/geometry/geometries/multi_polygon.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/relate.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace sym_difference { template <typename GeometryOut> struct compute_difference { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return geometry::dispatch::intersection_insert < Geometry1, Geometry2, GeometryOut, overlay_difference, geometry::detail::overlay::do_reverse < geometry::point_order<Geometry1>::value >::value, geometry::detail::overlay::do_reverse < geometry::point_order<Geometry2>::value, true >::value >::apply(geometry1, geometry2, robust_policy, out, strategy); } }; template <typename GeometryOut, typename Geometry1, typename Geometry2> struct sym_difference_generic { template < typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { out = compute_difference < GeometryOut >::apply(geometry1, geometry2, robust_policy, out, strategy); return compute_difference < GeometryOut >::apply(geometry2, geometry1, robust_policy, out, strategy); } }; template <typename GeometryOut, typename Areal1, typename Areal2> struct sym_difference_areal_areal { template < typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Areal1 const& areal1, Areal2 const& areal2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { typedef geometry::model::multi_polygon < GeometryOut > helper_geometry_type; helper_geometry_type diff12, diff21; std::back_insert_iterator<helper_geometry_type> oit12(diff12); std::back_insert_iterator<helper_geometry_type> oit21(diff21); compute_difference < GeometryOut >::apply(areal1, areal2, robust_policy, oit12, strategy); compute_difference < GeometryOut >::apply(areal2, areal1, robust_policy, oit21, strategy); return geometry::dispatch::union_insert < helper_geometry_type, helper_geometry_type, GeometryOut >::apply(diff12, diff21, robust_policy, out, strategy); } }; template < typename GeometryOut, typename SingleTag, template <typename, typename, typename> class Algorithm > struct sym_difference_same_inputs_tupled_output { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_access < GeometryOut, SingleTag, SingleTag > access; access::get(out) = Algorithm < typename access::type, Geometry1, Geometry2 >::apply(geometry1, geometry2, robust_policy, access::get(out), strategy); return out; } }; template < typename GeometryOut, typename SingleTag1, typename SingleTag2, bool Reverse = (geometry::core_dispatch::top_dim<SingleTag1>::value > geometry::core_dispatch::top_dim<SingleTag2>::value) > struct sym_difference_different_inputs_tupled_output { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return sym_difference_different_inputs_tupled_output < GeometryOut, SingleTag2, SingleTag1 >::apply(geometry2, geometry1, robust_policy, out, strategy); } }; template < typename GeometryOut, typename SingleTag1, typename SingleTag2 > struct sym_difference_different_inputs_tupled_output < GeometryOut, SingleTag1, SingleTag2, false > { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_access < GeometryOut, SingleTag1, SingleTag1 > access1; typedef typename geometry::detail::output_geometry_access < GeometryOut, SingleTag2, SingleTag2 > access2; access1::get(out) = compute_difference < typename access1::type >::apply(geometry1, geometry2, robust_policy, access1::get(out), strategy); access2::get(out) = geometry::detail::convert_to_output < Geometry2, typename access2::type >::apply(geometry2, access2::get(out)); return out; } }; }} // namespace detail::sym_difference #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename GeometryOut, typename TagIn1 = typename geometry::tag_cast < typename tag<Geometry1>::type, pointlike_tag, linear_tag, areal_tag >::type, typename TagIn2 = typename geometry::tag_cast < typename tag<Geometry2>::type, pointlike_tag, linear_tag, areal_tag >::type, typename TagOut = typename detail::setop_insert_output_tag<GeometryOut>::type > struct sym_difference_insert : detail::sym_difference::sym_difference_generic < GeometryOut, Geometry1, Geometry2 > {}; template < typename Areal1, typename Areal2, typename GeometryOut, typename TagOut > struct sym_difference_insert < Areal1, Areal2, GeometryOut, areal_tag, areal_tag, TagOut > : detail::sym_difference::sym_difference_areal_areal < GeometryOut, Areal1, Areal2 > {}; template < typename PointLike1, typename PointLike2, typename GeometryOut > struct sym_difference_insert < PointLike1, PointLike2, GeometryOut, pointlike_tag, pointlike_tag, detail::tupled_output_tag > : detail::expect_output<PointLike1, PointLike2, GeometryOut, point_tag> , detail::sym_difference::sym_difference_same_inputs_tupled_output < GeometryOut, point_tag, detail::sym_difference::sym_difference_generic > {}; template < typename Linear1, typename Linear2, typename GeometryOut > struct sym_difference_insert < Linear1, Linear2, GeometryOut, linear_tag, linear_tag, detail::tupled_output_tag > : detail::expect_output<Linear1, Linear2, GeometryOut, linestring_tag> , detail::sym_difference::sym_difference_same_inputs_tupled_output < GeometryOut, linestring_tag, detail::sym_difference::sym_difference_generic > {}; template < typename Areal1, typename Areal2, typename GeometryOut > struct sym_difference_insert < Areal1, Areal2, GeometryOut, areal_tag, areal_tag, detail::tupled_output_tag > : detail::expect_output<Areal1, Areal2, GeometryOut, polygon_tag> , detail::sym_difference::sym_difference_same_inputs_tupled_output < GeometryOut, polygon_tag, detail::sym_difference::sym_difference_areal_areal > {}; template < typename Geometry1, typename Geometry2, typename GeometryOut, typename TagIn1, typename TagIn2 > struct sym_difference_insert < Geometry1, Geometry2, GeometryOut, TagIn1, TagIn2, detail::tupled_output_tag > : detail::expect_output < Geometry1, Geometry2, GeometryOut, typename detail::single_tag_from_base_tag<TagIn1>::type, typename detail::single_tag_from_base_tag<TagIn2>::type > , detail::sym_difference::sym_difference_different_inputs_tupled_output < GeometryOut, typename detail::single_tag_from_base_tag<TagIn1>::type, typename detail::single_tag_from_base_tag<TagIn2>::type > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace sym_difference { /*! \brief \brief_calc2{symmetric difference} \brief_strategy \ingroup sym_difference \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)} \brief_strategy. \details_insert{sym_difference} \tparam GeometryOut output geometry type, must be specified \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy_overlay \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{difference} \param strategy \param_strategy{difference} \return \return_out \qbk{distinguish,with strategy} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator, typename Strategy > inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); //concepts::check<GeometryOut>(); geometry::detail::output_geometry_concept_check<GeometryOut>::apply(); typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return dispatch::sym_difference_insert < Geometry1, Geometry2, GeometryOut >::apply(geometry1, geometry2, robust_policy, out, strategy); } /*! \brief \brief_calc2{symmetric difference} \ingroup sym_difference \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)} \details_insert{sym_difference} \tparam GeometryOut output geometry type, must be specified \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{difference} \return \return_out */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator > inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { typedef typename strategy::intersection::services::default_strategy < typename cs_tag<GeometryOut>::type >::type strategy_type; return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type()); } }} // namespace detail::sym_difference #endif // DOXYGEN_NO_DETAIL namespace resolve_strategy { struct sym_difference { template < typename Geometry1, typename Geometry2, typename Collection, typename Strategy > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection & output_collection, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_value < Collection >::type single_out; detail::sym_difference::sym_difference_insert<single_out>( geometry1, geometry2, geometry::detail::output_geometry_back_inserter(output_collection), strategy); } template < typename Geometry1, typename Geometry2, typename Collection > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection & output_collection, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; apply(geometry1, geometry2, output_collection, strategy_type()); } }; } // resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct sym_difference { template <typename Collection, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { resolve_strategy::sym_difference::apply(geometry1, geometry2, output_collection, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Geometry2 const& m_geometry2; Collection& m_output_collection; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) : m_geometry2(geometry2) , m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry1> void operator()(Geometry1 const& geometry1) const { sym_difference < Geometry1, Geometry2 >::apply(geometry1, m_geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(geometry2, output_collection, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct sym_difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Geometry1 const& m_geometry1; Collection& m_output_collection; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Collection& output_collection, Strategy const& strategy) : m_geometry1(geometry1) , m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry2> void operator()(Geometry2 const& geometry2) const { sym_difference < Geometry1, Geometry2 >::apply(m_geometry1, geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(Geometry1 const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(geometry1, output_collection, strategy), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Collection& m_output_collection; Strategy const& m_strategy; visitor(Collection& output_collection, Strategy const& strategy) : m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> void operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { sym_difference < Geometry1, Geometry2 >::apply(geometry1, geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(output_collection, strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_calc2{symmetric difference} \ingroup sym_difference \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection output collection, either a multi-geometry, or a std::vector<Geometry> / std::deque<Geometry> etc \tparam Strategy \tparam_strategy{Sym_difference} \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection \param strategy \param_strategy{sym_difference} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/sym_difference.qbk]} */ template < typename Geometry1, typename Geometry2, typename Collection, typename Strategy > inline void sym_difference(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { resolve_variant::sym_difference < Geometry1, Geometry2 >::apply(geometry1, geometry2, output_collection, strategy); } /*! \brief \brief_calc2{symmetric difference} \ingroup sym_difference \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection output collection, either a multi-geometry, or a std::vector<Geometry> / std::deque<Geometry> etc \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection \qbk{[include reference/algorithms/sym_difference.qbk]} */ template < typename Geometry1, typename Geometry2, typename Collection > inline void sym_difference(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection) { resolve_variant::sym_difference < Geometry1, Geometry2 >::apply(geometry1, geometry2, output_collection, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP crosses.hpp 0000644 00000020436 15125631656 0006755 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2014, 2017. // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP #define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP #include <cstddef> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > struct crosses : detail::relate::relate_impl < detail::de9im::static_mask_crosses_type, Geometry1, Geometry2 > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct crosses { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct crosses { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_strategy::crosses::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: static_visitor<bool> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) , m_strategy(strategy) {} template <typename Geometry1> result_type operator()(Geometry1 const& geometry1) const { return crosses < Geometry1, Geometry2 >::apply(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct crosses<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: static_visitor<bool> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) , m_strategy(strategy) {} template <typename Geometry2> result_type operator()(Geometry2 const& geometry2) const { return crosses < Geometry1, Geometry2 >::apply(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct crosses<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> result_type operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return crosses < Geometry1, Geometry2 >::apply(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_check2{crosses} \ingroup crosses \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Crosses} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{crosses} \return \return_check2{crosses} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/crosses.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::crosses < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief \brief_check2{crosses} \ingroup crosses \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{crosses} \qbk{[include reference/algorithms/crosses.qbk]} \qbk{ [heading Examples] [crosses] [crosses_output] } */ template <typename Geometry1, typename Geometry2> inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::crosses < Geometry1, Geometry2 >::apply(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP num_points.hpp 0000644 00000013030 15125631656 0007457 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_NUM_POINTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_NUM_POINTS_HPP #include <cstddef> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/counting.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace num_points { template <bool AddForOpen> struct range_count { template <typename Range> static inline std::size_t apply(Range const& range) { std::size_t n = boost::size(range); if (AddForOpen && n > 0 && geometry::closure<Range>::value == open ) { return n + 1; } return n; } }; }} // namespace detail::num_points #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, bool AddForOpen, typename Tag = typename tag_cast < typename tag<Geometry>::type, multi_tag >::type > struct num_points: not_implemented<Tag> {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, point_tag> : detail::counting::other_count<1> {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, box_tag> : detail::counting::other_count<(1 << geometry::dimension<Geometry>::value)> {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, segment_tag> : detail::counting::other_count<2> {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, linestring_tag> : detail::num_points::range_count<AddForOpen> {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, ring_tag> : detail::num_points::range_count<AddForOpen> {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, polygon_tag> : detail::counting::polygon_count < detail::num_points::range_count<AddForOpen> > {}; template <typename Geometry, bool AddForOpen> struct num_points<Geometry, AddForOpen, multi_tag> : detail::counting::multi_count < num_points<typename boost::range_value<Geometry>::type, AddForOpen> > {}; } // namespace dispatch #endif namespace resolve_variant { template <typename Geometry> struct num_points { static inline std::size_t apply(Geometry const& geometry, bool add_for_open) { concepts::check<Geometry const>(); return add_for_open ? dispatch::num_points<Geometry, true>::apply(geometry) : dispatch::num_points<Geometry, false>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct num_points<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<std::size_t> { bool m_add_for_open; visitor(bool add_for_open): m_add_for_open(add_for_open) {} template <typename Geometry> inline std::size_t operator()(Geometry const& geometry) const { return num_points<Geometry>::apply(geometry, m_add_for_open); } }; static inline std::size_t apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, bool add_for_open) { return boost::apply_visitor(visitor(add_for_open), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{number of points} \ingroup num_points \details \details_calc{num_points, number of points}. \tparam Geometry \tparam_geometry \param geometry \param_geometry \param add_for_open add one for open geometries (i.e. polygon types which are not closed) \return \return_calc{number of points} \qbk{[include reference/algorithms/num_points.qbk]} */ template <typename Geometry> inline std::size_t num_points(Geometry const& geometry, bool add_for_open = false) { return resolve_variant::num_points<Geometry>::apply(geometry, add_for_open); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_NUM_POINTS_HPP is_simple.hpp 0000644 00000001077 15125631656 0007260 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP #define BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP #include <boost/geometry/algorithms/detail/is_simple/interface.hpp> #include <boost/geometry/algorithms/detail/is_simple/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP intersects.hpp 0000644 00000002171 15125631656 0007453 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013-2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP #include <boost/geometry/algorithms/detail/intersects/interface.hpp> #include <boost/geometry/algorithms/detail/intersects/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP remove_spikes.hpp 0000644 00000023066 15125631656 0010151 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2013 Bruno Lalande, Paris, France. // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP #define BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP #include <deque> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> /* Remove spikes from a ring/polygon. Ring (having 8 vertices, including closing vertex) +------+ | | | +--+ | | ^this "spike" is removed, can be located outside/inside the ring +------+ (the actualy determination if it is removed is done by a strategy) */ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace remove_spikes { struct range_remove_spikes { template <typename Range, typename SideStrategy> static inline void apply(Range& range, SideStrategy const& strategy) { typedef typename point_type<Range>::type point_type; std::size_t n = boost::size(range); std::size_t const min_num_points = core_detail::closure::minimum_ring_size < geometry::closure<Range>::value >::value - 1; // subtract one: a polygon with only one spike should result into one point if (n < min_num_points) { return; } std::vector<point_type> cleaned; cleaned.reserve(n); for (typename boost::range_iterator<Range const>::type it = boost::begin(range); it != boost::end(range); ++it) { // Add point cleaned.push_back(*it); while(cleaned.size() >= 3 && detail::is_spike_or_equal(range::at(cleaned, cleaned.size() - 3), range::at(cleaned, cleaned.size() - 2), range::back(cleaned), strategy)) { // Remove pen-ultimate point causing the spike (or which was equal) cleaned.erase(cleaned.end() - 2); } } typedef typename std::vector<point_type>::iterator cleaned_iterator; cleaned_iterator cleaned_b = cleaned.begin(); cleaned_iterator cleaned_e = cleaned.end(); std::size_t cleaned_count = cleaned.size(); // For a closed-polygon, remove closing point, this makes checking first point(s) easier and consistent if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) ) { --cleaned_e; --cleaned_count; } bool found = false; do { found = false; // Check for spike in first point while(cleaned_count >= 3 && detail::is_spike_or_equal(*(cleaned_e - 2), // prev *(cleaned_e - 1), // back *(cleaned_b), // front strategy)) { --cleaned_e; --cleaned_count; found = true; } // Check for spike in second point while(cleaned_count >= 3 && detail::is_spike_or_equal(*(cleaned_e - 1), // back *(cleaned_b), // front *(cleaned_b + 1), // next strategy)) { ++cleaned_b; --cleaned_count; found = true; } } while (found); if (cleaned_count == 2) { // Ticket #9871: open polygon with only two points. // the second point forms, by definition, a spike --cleaned_e; //--cleaned_count; } // Close if necessary if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) ) { BOOST_GEOMETRY_ASSERT(cleaned_e != cleaned.end()); *cleaned_e = *cleaned_b; ++cleaned_e; //++cleaned_count; } // Copy output geometry::clear(range); std::copy(cleaned_b, cleaned_e, range::back_inserter(range)); } }; struct polygon_remove_spikes { template <typename Polygon, typename SideStrategy> static inline void apply(Polygon& polygon, SideStrategy const& strategy) { typedef range_remove_spikes per_range; per_range::apply(exterior_ring(polygon), strategy); typename interior_return_type<Polygon>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon>::type it = boost::begin(rings); it != boost::end(rings); ++it) { per_range::apply(*it, strategy); } } }; template <typename SingleVersion> struct multi_remove_spikes { template <typename MultiGeometry, typename SideStrategy> static inline void apply(MultiGeometry& multi, SideStrategy const& strategy) { for (typename boost::range_iterator<MultiGeometry>::type it = boost::begin(multi); it != boost::end(multi); ++it) { SingleVersion::apply(*it, strategy); } } }; }} // namespace detail::remove_spikes #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct remove_spikes { template <typename SideStrategy> static inline void apply(Geometry&, SideStrategy const&) {} }; template <typename Ring> struct remove_spikes<Ring, ring_tag> : detail::remove_spikes::range_remove_spikes {}; template <typename Polygon> struct remove_spikes<Polygon, polygon_tag> : detail::remove_spikes::polygon_remove_spikes {}; template <typename MultiPolygon> struct remove_spikes<MultiPolygon, multi_polygon_tag> : detail::remove_spikes::multi_remove_spikes < detail::remove_spikes::polygon_remove_spikes > {}; } // namespace dispatch #endif namespace resolve_variant { template <typename Geometry> struct remove_spikes { template <typename Strategy> static void apply(Geometry& geometry, Strategy const& strategy) { concepts::check<Geometry>(); dispatch::remove_spikes<Geometry>::apply(geometry, strategy); } static void apply(Geometry& geometry, geometry::default_strategy const&) { typedef typename strategy::side::services::default_strategy < typename cs_tag<Geometry>::type >::type side_strategy; apply(geometry, side_strategy()); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<void> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry> void operator()(Geometry& geometry) const { remove_spikes<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy) { boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant /*! \ingroup remove_spikes \tparam Geometry geometry type \param geometry the geometry to make remove_spikes */ template <typename Geometry> inline void remove_spikes(Geometry& geometry) { resolve_variant::remove_spikes<Geometry>::apply(geometry, geometry::default_strategy()); } /*! \ingroup remove_spikes \tparam Geometry geometry type \tparam Strategy side strategy type \param geometry the geometry to make remove_spikes \param strategy the side strategy used by the algorithm */ template <typename Geometry, typename Strategy> inline void remove_spikes(Geometry& geometry, Strategy const& strategy) { resolve_variant::remove_spikes<Geometry>::apply(geometry, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP overlaps.hpp 0000644 00000002053 15125631656 0007122 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014, 2015, 2017. // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP #define BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP #include <boost/geometry/algorithms/detail/overlaps/interface.hpp> #include <boost/geometry/algorithms/detail/overlaps/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP densify.hpp 0000644 00000030270 15125631656 0006732 0 ustar 00 // 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 <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/exception.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/densify.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/throw_exception.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace densify { template <typename Range> struct push_back_policy { typedef typename boost::range_value<Range>::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 <typename Range, typename Point> inline void convert_and_push_back(Range & range, Point const& p) { typename boost::range_value<Range>::type p2; geometry::detail::conversion::convert_point_to_point(p, p2); range::push_back(range, p2); } template <bool AppendLastPoint = true> struct densify_range { template <typename FwdRng, typename MutRng, typename T, typename Strategy> static inline void apply(FwdRng const& rng, MutRng & rng_out, T const& len, Strategy const& strategy) { typedef typename boost::range_iterator<FwdRng const>::type iterator_t; typedef typename boost::range_value<FwdRng>::type point_t; iterator_t it = boost::begin(rng); iterator_t end = boost::end(rng); if (it == end) // empty(rng) { return; } push_back_policy<MutRng> 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 <bool IsClosed1, bool IsClosed2> // false, X struct densify_ring { template <typename Geometry, typename GeometryOut, typename T, typename Strategy> static inline void apply(Geometry const& ring, GeometryOut & ring_out, T const& len, Strategy const& strategy) { geometry::detail::densify::densify_range<true> ::apply(ring, ring_out, len, strategy); if (boost::size(ring) <= 1) return; typedef typename point_type<Geometry>::type point_t; point_t const& p0 = range::back(ring); point_t const& p1 = range::front(ring); push_back_policy<GeometryOut> 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<true, true> : densify_range<true> {}; template <> struct densify_ring<true, false> : densify_range<false> {}; }} // namespace detail::densify #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename GeometryOut, typename Tag1 = typename tag<Geometry>::type, typename Tag2 = typename tag<GeometryOut>::type > struct densify : not_implemented<Tag1, Tag2> {}; template <typename Geometry, typename GeometryOut> struct densify<Geometry, GeometryOut, linestring_tag, linestring_tag> : geometry::detail::densify::densify_range<> {}; template <typename Geometry, typename GeometryOut> struct densify<Geometry, GeometryOut, multi_linestring_tag, multi_linestring_tag> { template <typename T, typename Strategy> 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 <typename Geometry, typename GeometryOut> struct densify<Geometry, GeometryOut, ring_tag, ring_tag> : geometry::detail::densify::densify_ring < geometry::closure<Geometry>::value != geometry::open, geometry::closure<GeometryOut>::value != geometry::open > {}; template <typename Geometry, typename GeometryOut> struct densify<Geometry, GeometryOut, polygon_tag, polygon_tag> { template <typename T, typename Strategy> 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 <typename Ring, typename RingOut, typename T, typename Strategy> static void apply_ring(Ring const& ring, RingOut & ring_out, T const& len, Strategy const& strategy) { densify<Ring, RingOut, ring_tag, ring_tag> ::apply(ring, ring_out, len, strategy); } }; template <typename Geometry, typename GeometryOut> struct densify<Geometry, GeometryOut, multi_polygon_tag, multi_polygon_tag> { template <typename T, typename Strategy> 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 <typename Poly, typename PolyOut, typename T, typename Strategy> static void apply_poly(Poly const& poly, PolyOut & poly_out, T const& len, Strategy const& strategy) { densify<Poly, PolyOut, polygon_tag, polygon_tag>:: apply(poly, poly_out, len, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct densify { template <typename Geometry, typename Distance, typename Strategy> static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { dispatch::densify<Geometry, Geometry> ::apply(geometry, out, max_distance, strategy); } template <typename Geometry, typename Distance> 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<Geometry>::type >::type strategy_type; /*BOOST_CONCEPT_ASSERT( (concepts::DensifyStrategy<strategy_type>) );*/ apply(geometry, out, max_distance, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct densify { template <typename Distance, typename Strategy> 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 <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct densify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Distance, typename Strategy> struct visitor: boost::static_visitor<void> { 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 <typename Geometry> void operator()(Geometry const& geometry, Geometry& out) const { densify<Geometry>::apply(geometry, out, m_max_distance, m_strategy); } }; template <typename Distance, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out, Distance const& max_distance, Strategy const& strategy) { boost::apply_visitor( visitor<Distance, Strategy>(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 <typename Geometry, typename Distance, typename Strategy> inline void densify(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { concepts::check<Geometry>(); 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 <typename Geometry, typename Distance> 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 convert.hpp 0000644 00000041746 15125631656 0006763 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP #define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP #include <cstddef> #include <type_traits> #include <boost/numeric/conversion/cast.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { // Silence warning C4127: conditional expression is constant // Silence warning C4512: assignment operator could not be generated #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127 4512) #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace conversion { template < typename Point, typename Box, std::size_t Index, std::size_t Dimension, std::size_t DimensionCount > struct point_to_box { static inline void apply(Point const& point, Box& box) { typedef typename coordinate_type<Box>::type coordinate_type; set<Index, Dimension>(box, boost::numeric_cast<coordinate_type>(get<Dimension>(point))); point_to_box < Point, Box, Index, Dimension + 1, DimensionCount >::apply(point, box); } }; template < typename Point, typename Box, std::size_t Index, std::size_t DimensionCount > struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount> { static inline void apply(Point const& , Box& ) {} }; template <typename Box, typename Range, bool Close, bool Reverse> struct box_to_range { static inline void apply(Box const& box, Range& range) { traits::resize<Range>::apply(range, Close ? 5 : 4); assign_box_corners_oriented<Reverse>(box, range); if (Close) { range::at(range, 4) = range::at(range, 0); } } }; template <typename Segment, typename Range> struct segment_to_range { static inline void apply(Segment const& segment, Range& range) { traits::resize<Range>::apply(range, 2); typename boost::range_iterator<Range>::type it = boost::begin(range); assign_point_from_index<0>(segment, *it); ++it; assign_point_from_index<1>(segment, *it); } }; template < typename Range1, typename Range2, bool Reverse = false > struct range_to_range { typedef typename reversible_view < Range1 const, Reverse ? iterate_reverse : iterate_forward >::type rview_type; typedef typename closeable_view < rview_type const, geometry::closure<Range1>::value >::type view_type; struct default_policy { template <typename Point1, typename Point2> static inline void apply(Point1 const& point1, Point2 & point2) { geometry::detail::conversion::convert_point_to_point(point1, point2); } }; static inline void apply(Range1 const& source, Range2& destination) { apply(source, destination, default_policy()); } template <typename ConvertPointPolicy> static inline ConvertPointPolicy apply(Range1 const& source, Range2& destination, ConvertPointPolicy convert_point) { geometry::clear(destination); rview_type rview(source); // We consider input always as closed, and skip last // point for open output. view_type view(rview); typedef typename boost::range_size<Range1>::type size_type; size_type n = boost::size(view); if (geometry::closure<Range2>::value == geometry::open) { n--; } // If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max() // but ok, sice below it == end() size_type i = 0; for (typename boost::range_iterator<view_type const>::type it = boost::begin(view); it != boost::end(view) && i < n; ++it, ++i) { typename boost::range_value<Range2>::type point; convert_point.apply(*it, point); range::push_back(destination, point); } return convert_point; } }; template <typename Polygon1, typename Polygon2> struct polygon_to_polygon { typedef range_to_range < typename geometry::ring_type<Polygon1>::type, typename geometry::ring_type<Polygon2>::type, geometry::point_order<Polygon1>::value != geometry::point_order<Polygon2>::value > per_ring; static inline void apply(Polygon1 const& source, Polygon2& destination) { // Clearing managed per ring, and in the resizing of interior rings per_ring::apply(geometry::exterior_ring(source), geometry::exterior_ring(destination)); // Container should be resizeable traits::resize < typename std::remove_reference < typename traits::interior_mutable_type<Polygon2>::type >::type >::apply(interior_rings(destination), num_interior_rings(source)); typename interior_return_type<Polygon1 const>::type rings_source = interior_rings(source); typename interior_return_type<Polygon2>::type rings_dest = interior_rings(destination); typename detail::interior_iterator<Polygon1 const>::type it_source = boost::begin(rings_source); typename detail::interior_iterator<Polygon2>::type it_dest = boost::begin(rings_dest); for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest) { per_ring::apply(*it_source, *it_dest); } } }; template <typename Single, typename Multi, typename Policy> struct single_to_multi: private Policy { static inline void apply(Single const& single, Multi& multi) { traits::resize<Multi>::apply(multi, 1); Policy::apply(single, *boost::begin(multi)); } }; template <typename Multi1, typename Multi2, typename Policy> struct multi_to_multi: private Policy { static inline void apply(Multi1 const& multi1, Multi2& multi2) { traits::resize<Multi2>::apply(multi2, boost::size(multi1)); typename boost::range_iterator<Multi1 const>::type it1 = boost::begin(multi1); typename boost::range_iterator<Multi2>::type it2 = boost::begin(multi2); for (; it1 != boost::end(multi1); ++it1, ++it2) { Policy::apply(*it1, *it2); } } }; }} // namespace detail::conversion #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type, typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type, std::size_t DimensionCount = dimension<Geometry1>::type::value, bool UseAssignment = std::is_same<Geometry1, Geometry2>::value && !std::is_array<Geometry1>::value > struct convert : not_implemented < Tag1, Tag2, std::integral_constant<std::size_t, DimensionCount> > {}; template < typename Geometry1, typename Geometry2, typename Tag, std::size_t DimensionCount > struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true> { // Same geometry type -> copy whole geometry static inline void apply(Geometry1 const& source, Geometry2& destination) { destination = source; } }; template < typename Geometry1, typename Geometry2, std::size_t DimensionCount > struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false> : detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount> {}; template < typename Box1, typename Box2, std::size_t DimensionCount > struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false> : detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount> {}; template < typename Segment1, typename Segment2, std::size_t DimensionCount > struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false> : detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount> {}; template <typename Segment, typename LineString, std::size_t DimensionCount> struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false> : detail::conversion::segment_to_range<Segment, LineString> {}; template <typename Ring1, typename Ring2, std::size_t DimensionCount> struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false> : detail::conversion::range_to_range < Ring1, Ring2, geometry::point_order<Ring1>::value != geometry::point_order<Ring2>::value > {}; template <typename LineString1, typename LineString2, std::size_t DimensionCount> struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false> : detail::conversion::range_to_range<LineString1, LineString2> {}; template <typename Polygon1, typename Polygon2, std::size_t DimensionCount> struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false> : detail::conversion::polygon_to_polygon<Polygon1, Polygon2> {}; template <typename Box, typename Ring> struct convert<Box, Ring, box_tag, ring_tag, 2, false> : detail::conversion::box_to_range < Box, Ring, geometry::closure<Ring>::value == closed, geometry::point_order<Ring>::value == counterclockwise > {}; template <typename Box, typename Polygon> struct convert<Box, Polygon, box_tag, polygon_tag, 2, false> { static inline void apply(Box const& box, Polygon& polygon) { typedef typename ring_type<Polygon>::type ring_type; convert < Box, ring_type, box_tag, ring_tag, 2, false >::apply(box, exterior_ring(polygon)); } }; template <typename Point, typename Box, std::size_t DimensionCount> struct convert<Point, Box, point_tag, box_tag, DimensionCount, false> { static inline void apply(Point const& point, Box& box) { detail::conversion::point_to_box < Point, Box, min_corner, 0, DimensionCount >::apply(point, box); detail::conversion::point_to_box < Point, Box, max_corner, 0, DimensionCount >::apply(point, box); } }; template <typename Ring, typename Polygon, std::size_t DimensionCount> struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false> { static inline void apply(Ring const& ring, Polygon& polygon) { typedef typename ring_type<Polygon>::type ring_type; convert < Ring, ring_type, ring_tag, ring_tag, DimensionCount, false >::apply(ring, exterior_ring(polygon)); } }; template <typename Polygon, typename Ring, std::size_t DimensionCount> struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false> { static inline void apply(Polygon const& polygon, Ring& ring) { typedef typename ring_type<Polygon>::type ring_type; convert < ring_type, Ring, ring_tag, ring_tag, DimensionCount, false >::apply(exterior_ring(polygon), ring); } }; // Dispatch for multi <-> multi, specifying their single-version as policy. // Note that, even if the multi-types are mutually different, their single // version types might be the same and therefore we call std::is_same again template <typename Multi1, typename Multi2, std::size_t DimensionCount> struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false> : detail::conversion::multi_to_multi < Multi1, Multi2, convert < typename boost::range_value<Multi1>::type, typename boost::range_value<Multi2>::type, typename single_tag_of < typename tag<Multi1>::type >::type, typename single_tag_of < typename tag<Multi2>::type >::type, DimensionCount > > {}; template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount> struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false> : detail::conversion::single_to_multi < Single, Multi, convert < Single, typename boost::range_value<Multi>::type, typename tag<Single>::type, typename single_tag_of < typename tag<Multi>::type >::type, DimensionCount, false > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct convert { static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2) { concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>(); dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { struct visitor: static_visitor<void> { Geometry2& m_geometry2; visitor(Geometry2& geometry2) : m_geometry2(geometry2) {} template <typename Geometry1> inline void operator()(Geometry1 const& geometry1) const { convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2); } }; static inline void apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2& geometry2 ) { boost::apply_visitor(visitor(geometry2), geometry1); } }; } /*! \brief Converts one geometry to another geometry \details The convert algorithm converts one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only works if it is possible and applicable. If the point-order is different, or the closure is different between two geometry types, it will be converted correctly by explicitly reversing the points or closing or opening the polygon rings. \ingroup convert \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry (source) \param geometry2 \param_geometry (target) \qbk{[include reference/algorithms/convert.qbk]} */ template <typename Geometry1, typename Geometry2> inline void convert(Geometry1 const& geometry1, Geometry2& geometry2) { resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP point_on_surface.hpp 0000644 00000032003 15125631656 0010622 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2013 Bruno Lalande, Paris, France. // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP #include <cstddef> #include <numeric> #include <boost/concept_check.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/extreme_points.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp> #include <boost/geometry/strategies/side.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace point_on_surface { template <typename CoordinateType, int Dimension> struct specific_coordinate_first { CoordinateType const m_value_to_be_first; inline specific_coordinate_first(CoordinateType value_to_be_skipped) : m_value_to_be_first(value_to_be_skipped) {} template <typename Point> inline bool operator()(Point const& lhs, Point const& rhs) { CoordinateType const lh = geometry::get<Dimension>(lhs); CoordinateType const rh = geometry::get<Dimension>(rhs); // If both lhs and rhs equal m_value_to_be_first, // we should handle conform if lh < rh = FALSE // The first condition meets that, keep it first if (geometry::math::equals(rh, m_value_to_be_first)) { // Handle conform lh < -INF, which is always false return false; } if (geometry::math::equals(lh, m_value_to_be_first)) { // Handle conform -INF < rh, which is always true return true; } return lh < rh; } }; template <int Dimension, typename Collection, typename Value, typename Predicate> inline bool max_value(Collection const& collection, Value& the_max, Predicate const& predicate) { bool first = true; for (typename Collection::const_iterator it = collection.begin(); it != collection.end(); ++it) { if (! it->empty()) { Value the_value = geometry::get<Dimension>(*std::max_element(it->begin(), it->end(), predicate)); if (first || the_value > the_max) { the_max = the_value; first = false; } } } return ! first; } template <int Dimension, typename Value> struct select_below { Value m_value; inline select_below(Value const& v) : m_value(v) {} template <typename Intruder> inline bool operator()(Intruder const& intruder) const { if (intruder.empty()) { return true; } Value max = geometry::get<Dimension>(*std::max_element(intruder.begin(), intruder.end(), detail::extreme_points::compare<Dimension>())); return geometry::math::equals(max, m_value) || max < m_value; } }; template <int Dimension, typename Value> struct adapt_base { Value m_value; inline adapt_base(Value const& v) : m_value(v) {} template <typename Intruder> inline void operator()(Intruder& intruder) const { if (intruder.size() >= 3) { detail::extreme_points::move_along_vector<Dimension>(intruder, m_value); } } }; template <int Dimension, typename Value> struct min_of_intruder { template <typename Intruder> inline bool operator()(Intruder const& lhs, Intruder const& rhs) const { Value lhs_min = geometry::get<Dimension>(*std::min_element(lhs.begin(), lhs.end(), detail::extreme_points::compare<Dimension>())); Value rhs_min = geometry::get<Dimension>(*std::min_element(rhs.begin(), rhs.end(), detail::extreme_points::compare<Dimension>())); return lhs_min < rhs_min; } }; template <typename Point, typename P> inline void calculate_average(Point& point, std::vector<P> const& points) { typedef typename geometry::coordinate_type<Point>::type coordinate_type; typedef typename std::vector<P>::const_iterator iterator_type; coordinate_type x = 0; coordinate_type y = 0; iterator_type end = points.end(); for ( iterator_type it = points.begin() ; it != end ; ++it) { x += geometry::get<0>(*it); y += geometry::get<1>(*it); } signed_size_type const count = points.size(); geometry::set<0>(point, x / count); geometry::set<1>(point, y / count); } template <int Dimension, typename Extremes, typename Intruders, typename CoordinateType> inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders& intruders, CoordinateType const& max_intruder) { // This function handles self-tangencies. // Self-tangencies use, as usual, the major part of code... // ___ e // /|\ \ . // / | \ \ . // / | \ \ . // / | \ \ . // / /\ | \ \ . // i2 i1 // The picture above shows the extreme (outside, "e") and two intruders ("i1","i2") // Assume that "i1" is self-tangent with the extreme, in one point at the top // Now the "penultimate" value is searched, this is is the top of i2 // Then everything including and below (this is "i2" here) is removed // Then the base of "i1" and of "e" is adapted to this penultimate value // It then looks like: // b ___ e // /|\ \ . // / | \ \ . // / | \ \ . // / | \ \ . // a c i1 // Then intruders (here "i1" but there may be more) are sorted from left to right // Finally points "a","b" and "c" (in this order) are selected as a new triangle. // This triangle will have a centroid which is inside (assumed that intruders left segment // is not equal to extremes left segment, but that polygon would be invalid) // Find highest non-self tangent intrusion, if any CoordinateType penultimate_value; specific_coordinate_first<CoordinateType, Dimension> pu_compare(max_intruder); if (max_value<Dimension>(intruders, penultimate_value, pu_compare)) { // Throw away all intrusions <= this value, and of the kept one set this as base. select_below<Dimension, CoordinateType> predicate(penultimate_value); intruders.erase ( std::remove_if(boost::begin(intruders), boost::end(intruders), predicate), boost::end(intruders) ); adapt_base<Dimension, CoordinateType> fe_predicate(penultimate_value); // Sort from left to right (or bottom to top if Dimension=0) std::for_each(boost::begin(intruders), boost::end(intruders), fe_predicate); // Also adapt base of extremes detail::extreme_points::move_along_vector<Dimension>(extremes, penultimate_value); } // Then sort in 1-Dim. Take first to calc centroid. std::sort(boost::begin(intruders), boost::end(intruders), min_of_intruder<1 - Dimension, CoordinateType>()); Extremes triangle; triangle.reserve(3); // Make a triangle of first two points of extremes (the ramp, from left to right), and last point of first intruder (which goes from right to left) std::copy(extremes.begin(), extremes.begin() + 2, std::back_inserter(triangle)); triangle.push_back(intruders.front().back()); // (alternatively we could use the last two points of extremes, and first point of last intruder...): //// ALTERNATIVE: std::copy(extremes.rbegin(), extremes.rbegin() + 2, std::back_inserter(triangle)); //// ALTERNATIVE: triangle.push_back(intruders.back().front()); // Now replace extremes with this smaller subset, a triangle, such that centroid calculation will result in a point inside extremes = triangle; } template <int Dimension, typename Geometry, typename Point, typename SideStrategy> inline bool calculate_point_on_surface(Geometry const& geometry, Point& point, SideStrategy const& strategy) { typedef typename geometry::point_type<Geometry>::type point_type; typedef typename geometry::coordinate_type<Geometry>::type coordinate_type; std::vector<point_type> extremes; typedef std::vector<std::vector<point_type> > intruders_type; intruders_type intruders; geometry::extreme_points<Dimension>(geometry, extremes, intruders, strategy); if (extremes.size() < 3) { return false; } // If there are intruders, find the max. if (! intruders.empty()) { coordinate_type max_intruder; detail::extreme_points::compare<Dimension> compare; if (max_value<Dimension>(intruders, max_intruder, compare)) { coordinate_type max_extreme = geometry::get<Dimension>(*std::max_element(extremes.begin(), extremes.end(), detail::extreme_points::compare<Dimension>())); if (max_extreme > max_intruder) { detail::extreme_points::move_along_vector<Dimension>(extremes, max_intruder); } else { replace_extremes_for_self_tangencies<Dimension>(extremes, intruders, max_intruder); } } } // Now calculate the average/centroid of the (possibly adapted) extremes calculate_average(point, extremes); return true; } }} // namespace detail::point_on_surface #endif // DOXYGEN_NO_DETAIL /*! \brief Assigns a Point guaranteed to lie on the surface of the Geometry \tparam Geometry geometry type. This also defines the type of the output point \param geometry Geometry to take point from \param point Point to assign \param strategy side strategy */ template <typename Geometry, typename Point, typename SideStrategy> inline void point_on_surface(Geometry const& geometry, Point & point, SideStrategy const& strategy) { concepts::check<Point>(); concepts::check<Geometry const>(); // First try in Y-direction (which should always succeed for valid polygons) if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point, strategy)) { // For invalid polygons, we might try X-direction detail::point_on_surface::calculate_point_on_surface<0>(geometry, point, strategy); } } /*! \brief Assigns a Point guaranteed to lie on the surface of the Geometry \tparam Geometry geometry type. This also defines the type of the output point \param geometry Geometry to take point from \param point Point to assign */ template <typename Geometry, typename Point> inline void point_on_surface(Geometry const& geometry, Point & point) { typedef typename strategy::side::services::default_strategy < typename cs_tag<Geometry>::type >::type strategy_type; point_on_surface(geometry, point, strategy_type()); } /*! \brief Returns point guaranteed to lie on the surface of the Geometry \tparam Geometry geometry type. This also defines the type of the output point \param geometry Geometry to take point from \param strategy side strategy \return The Point guaranteed to lie on the surface of the Geometry */ template<typename Geometry, typename SideStrategy> inline typename geometry::point_type<Geometry>::type return_point_on_surface(Geometry const& geometry, SideStrategy const& strategy) { typename geometry::point_type<Geometry>::type result; geometry::point_on_surface(geometry, result, strategy); return result; } /*! \brief Returns point guaranteed to lie on the surface of the Geometry \tparam Geometry geometry type. This also defines the type of the output point \param geometry Geometry to take point from \return The Point guaranteed to lie on the surface of the Geometry */ template<typename Geometry> inline typename geometry::point_type<Geometry>::type return_point_on_surface(Geometry const& geometry) { typename geometry::point_type<Geometry>::type result; geometry::point_on_surface(geometry, result); return result; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_POINT_ON_SURFACE_HPP comparable_distance.hpp 0000644 00000002123 15125631656 0011244 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP #include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp> #include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP is_convex.hpp 0000644 00000014554 15125631656 0007275 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017, 2018. // Modifications copyright (c) 2017-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP #define BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/side.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_convex { struct ring_is_convex { template <typename Ring, typename SideStrategy> static inline bool apply(Ring const& ring, SideStrategy const& strategy) { typename SideStrategy::equals_point_point_strategy_type eq_pp_strategy = strategy.get_equals_point_point_strategy(); std::size_t n = boost::size(ring); if (boost::size(ring) < core_detail::closure::minimum_ring_size < geometry::closure<Ring>::value >::value) { // (Too) small rings are considered as non-concave, is convex return true; } // Walk in clockwise direction, consider ring as closed // (though closure is not important in this algorithm - any dupped // point is skipped) typedef detail::normalized_view<Ring const> view_type; view_type view(ring); typedef geometry::ever_circling_range_iterator<view_type const> it_type; it_type previous(view); it_type current(view); current++; std::size_t index = 1; while (equals::equals_point_point(*current, *previous, eq_pp_strategy) && index < n) { current++; index++; } if (index == n) { // All points are apparently equal return true; } it_type next = current; next++; while (equals::equals_point_point(*current, *next, eq_pp_strategy)) { next++; } // We have now three different points on the ring // Walk through all points, use a counter because of the ever-circling // iterator for (std::size_t i = 0; i < n; i++) { int const side = strategy.apply(*previous, *current, *next); if (side == 1) { // Next is on the left side of clockwise ring: // the piece is not convex return false; } previous = current; current = next; // Advance next to next different point // (because there are non-equal points, this loop is not infinite) next++; while (equals::equals_point_point(*current, *next, eq_pp_strategy)) { next++; } } return true; } }; }} // namespace detail::is_convex #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct is_convex : not_implemented<Tag> {}; template <typename Box> struct is_convex<Box, box_tag> { template <typename Strategy> static inline bool apply(Box const& , Strategy const& ) { // Any box is convex (TODO: consider spherical boxes) return true; } }; template <typename Box> struct is_convex<Box, ring_tag> : detail::is_convex::ring_is_convex {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct is_convex { template <typename Strategy> static bool apply(Geometry const& geometry, Strategy const& strategy) { concepts::check<Geometry>(); return dispatch::is_convex<Geometry>::apply(geometry, strategy); } static bool apply(Geometry const& geometry, geometry::default_strategy const&) { typedef typename strategy::side::services::default_strategy < typename cs_tag<Geometry>::type >::type side_strategy; return apply(geometry, side_strategy()); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_convex<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry> bool operator()(Geometry const& geometry) const { return is_convex<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant // TODO: documentation / qbk template<typename Geometry> inline bool is_convex(Geometry const& geometry) { return resolve_variant::is_convex < Geometry >::apply(geometry, geometry::default_strategy()); } // TODO: documentation / qbk template<typename Geometry, typename Strategy> inline bool is_convex(Geometry const& geometry, Strategy const& strategy) { return resolve_variant::is_convex<Geometry>::apply(geometry, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP disjoint.hpp 0000644 00000002247 15125631656 0007117 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2014. // Modifications copyright (c) 2013-2014, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP #include <boost/geometry/algorithms/detail/disjoint/interface.hpp> #include <boost/geometry/algorithms/detail/disjoint/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DISJOINT_HPP simplify.hpp 0000644 00000054433 15125631656 0007134 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2018-2020. // Modifications copyright (c) 2018-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP #define BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP #include <cstddef> #include <set> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp> #include <boost/geometry/strategies/concepts/simplify_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/perimeter.hpp> #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace simplify { template <typename Range, typename EqualsStrategy> inline bool is_degenerate(Range const& range, EqualsStrategy const& strategy) { return boost::size(range) == 2 && detail::equals::equals_point_point(geometry::range::front(range), geometry::range::back(range), strategy); } struct simplify_range_insert { template<typename Range, typename Strategy, typename OutputIterator, typename Distance> static inline void apply(Range const& range, OutputIterator out, Distance const& max_distance, Strategy const& strategy) { typedef typename Strategy::distance_strategy_type::equals_point_point_strategy_type equals_strategy_type; boost::ignore_unused(strategy); if (is_degenerate(range, equals_strategy_type())) { std::copy(boost::begin(range), boost::begin(range) + 1, out); } else if (boost::size(range) <= 2 || max_distance < 0) { std::copy(boost::begin(range), boost::end(range), out); } else { strategy.apply(range, out, max_distance); } } }; struct simplify_copy { template <typename RangeIn, typename RangeOut, typename Strategy, typename Distance> static inline void apply(RangeIn const& range, RangeOut& out, Distance const& , Strategy const& ) { std::copy ( boost::begin(range), boost::end(range), geometry::range::back_inserter(out) ); } }; template <std::size_t MinimumToUseStrategy> struct simplify_range { template <typename RangeIn, typename RangeOut, typename Strategy, typename Distance> static inline void apply(RangeIn const& range, RangeOut& out, Distance const& max_distance, Strategy const& strategy) { typedef typename Strategy::distance_strategy_type::equals_point_point_strategy_type equals_strategy_type; // For a RING: // Note that, especially if max_distance is too large, // the output ring might be self intersecting while the input ring is // not, although chances are low in normal polygons if (boost::size(range) <= MinimumToUseStrategy || max_distance < 0) { simplify_copy::apply(range, out, max_distance, strategy); } else { simplify_range_insert::apply ( range, geometry::range::back_inserter(out), max_distance, strategy ); } // Verify the two remaining points are equal. If so, remove one of them. // This can cause the output being under the minimum size if (is_degenerate(out, equals_strategy_type())) { range::resize(out, 1); } } }; struct simplify_ring { private : template <typename Area> static inline int area_sign(Area const& area) { return area > 0 ? 1 : area < 0 ? -1 : 0; } template <typename Strategy, typename Ring> static std::size_t get_opposite(std::size_t index, Ring const& ring) { typename Strategy::distance_strategy_type distance_strategy; // Verify if it is NOT the case that all points are less than the // simplifying distance. If so, output is empty. typename Strategy::distance_type max_distance(-1); typename geometry::point_type<Ring>::type point = range::at(ring, index); std::size_t i = 0; for (typename boost::range_iterator<Ring const>::type it = boost::begin(ring); it != boost::end(ring); ++it, ++i) { // This actually is point-segment distance but will result // in point-point distance typename Strategy::distance_type dist = distance_strategy.apply(*it, point, point); if (dist > max_distance) { max_distance = dist; index = i; } } return index; } public : template <typename Ring, typename Strategy, typename Distance> static inline void apply(Ring const& ring, Ring& out, Distance const& max_distance, Strategy const& strategy) { std::size_t const size = boost::size(ring); if (size == 0) { return; } int const input_sign = area_sign(geometry::area(ring)); std::set<std::size_t> visited_indexes; // Rotate it into a copied vector // (vector, because source type might not support rotation) // (duplicate end point will be simplified away) typedef typename geometry::point_type<Ring>::type point_type; std::vector<point_type> rotated(size); // Closing point (but it will not start here) std::size_t index = 0; // Iterate (usually one iteration is enough) for (std::size_t iteration = 0; iteration < 4u; iteration++) { // Always take the opposite. Opposite guarantees that no point // "halfway" is chosen, creating an artefact (very narrow triangle) // Iteration 0: opposite to closing point (1/2, = on convex hull) // (this will start simplification with that point // and its opposite ~0) // Iteration 1: move a quarter on that ring, then opposite to 1/4 // (with its opposite 3/4) // Iteration 2: move an eight on that ring, then opposite (1/8) // Iteration 3: again move a quarter, then opposite (7/8) // So finally 8 "sides" of the ring have been examined (if it were // a semi-circle). Most probably, there are only 0 or 1 iterations. switch (iteration) { case 1 : index = (index + size / 4) % size; break; case 2 : index = (index + size / 8) % size; break; case 3 : index = (index + size / 4) % size; break; } index = get_opposite<Strategy>(index, ring); if (visited_indexes.count(index) > 0) { // Avoid trying the same starting point more than once continue; } std::rotate_copy(boost::begin(ring), range::pos(ring, index), boost::end(ring), rotated.begin()); // Close the rotated copy rotated.push_back(range::at(ring, index)); simplify_range<0>::apply(rotated, out, max_distance, strategy); // Verify that what was positive, stays positive (or goes to 0) // and what was negative stays negative (or goes to 0) int const output_sign = area_sign(geometry::area(out)); if (output_sign == input_sign) { // Result is considered as satisfactory (usually this is the // first iteration - only for small rings, having a scale // similar to simplify_distance, next iterations are tried return; } // Original is simplified away. Possibly there is a solution // when another starting point is used geometry::clear(out); if (iteration == 0 && geometry::perimeter(ring) < 3 * max_distance) { // Check if it is useful to iterate. A minimal triangle has a // perimeter of a bit more than 3 times the simplify distance return; } // Prepare next try visited_indexes.insert(index); rotated.resize(size); } } }; struct simplify_polygon { private: template < typename IteratorIn, typename InteriorRingsOut, typename Distance, typename Strategy > static inline void iterate(IteratorIn begin, IteratorIn end, InteriorRingsOut& interior_rings_out, Distance const& max_distance, Strategy const& strategy) { typedef typename boost::range_value<InteriorRingsOut>::type single_type; for (IteratorIn it = begin; it != end; ++it) { single_type out; simplify_ring::apply(*it, out, max_distance, strategy); if (! geometry::is_empty(out)) { range::push_back(interior_rings_out, out); } } } template < typename InteriorRingsIn, typename InteriorRingsOut, typename Distance, typename Strategy > static inline void apply_interior_rings( InteriorRingsIn const& interior_rings_in, InteriorRingsOut& interior_rings_out, Distance const& max_distance, Strategy const& strategy) { range::clear(interior_rings_out); iterate( boost::begin(interior_rings_in), boost::end(interior_rings_in), interior_rings_out, max_distance, strategy); } public: template <typename Polygon, typename Strategy, typename Distance> static inline void apply(Polygon const& poly_in, Polygon& poly_out, Distance const& max_distance, Strategy const& strategy) { // Note that if there are inner rings, and distance is too large, // they might intersect with the outer ring in the output, // while it didn't in the input. simplify_ring::apply(exterior_ring(poly_in), exterior_ring(poly_out), max_distance, strategy); apply_interior_rings(interior_rings(poly_in), interior_rings(poly_out), max_distance, strategy); } }; template<typename Policy> struct simplify_multi { template <typename MultiGeometry, typename Strategy, typename Distance> static inline void apply(MultiGeometry const& multi, MultiGeometry& out, Distance const& max_distance, Strategy const& strategy) { range::clear(out); typedef typename boost::range_value<MultiGeometry>::type single_type; for (typename boost::range_iterator<MultiGeometry const>::type it = boost::begin(multi); it != boost::end(multi); ++it) { single_type single_out; Policy::apply(*it, single_out, max_distance, strategy); if (! geometry::is_empty(single_out)) { range::push_back(out, single_out); } } } }; }} // namespace detail::simplify #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct simplify: not_implemented<Tag> {}; template <typename Point> struct simplify<Point, point_tag> { template <typename Distance, typename Strategy> static inline void apply(Point const& point, Point& out, Distance const& , Strategy const& ) { geometry::convert(point, out); } }; // Linestring, keep 2 points (unless those points are the same) template <typename Linestring> struct simplify<Linestring, linestring_tag> : detail::simplify::simplify_range<2> {}; template <typename Ring> struct simplify<Ring, ring_tag> : detail::simplify::simplify_ring {}; template <typename Polygon> struct simplify<Polygon, polygon_tag> : detail::simplify::simplify_polygon {}; template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct simplify_insert: not_implemented<Tag> {}; template <typename Linestring> struct simplify_insert<Linestring, linestring_tag> : detail::simplify::simplify_range_insert {}; template <typename Ring> struct simplify_insert<Ring, ring_tag> : detail::simplify::simplify_range_insert {}; template <typename MultiPoint> struct simplify<MultiPoint, multi_point_tag> : detail::simplify::simplify_copy {}; template <typename MultiLinestring> struct simplify<MultiLinestring, multi_linestring_tag> : detail::simplify::simplify_multi<detail::simplify::simplify_range<2> > {}; template <typename MultiPolygon> struct simplify<MultiPolygon, multi_polygon_tag> : detail::simplify::simplify_multi<detail::simplify::simplify_polygon> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct simplify { template <typename Geometry, typename Distance, typename Strategy> static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { dispatch::simplify<Geometry>::apply(geometry, out, max_distance, strategy); } template <typename Geometry, typename Distance> static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, default_strategy) { typedef typename point_type<Geometry>::type point_type; typedef typename strategy::distance::services::default_strategy < point_tag, segment_tag, point_type >::type ds_strategy_type; typedef strategy::simplify::douglas_peucker < point_type, ds_strategy_type > strategy_type; BOOST_CONCEPT_ASSERT( (concepts::SimplifyStrategy<strategy_type, point_type>) ); apply(geometry, out, max_distance, strategy_type()); } }; struct simplify_insert { template < typename Geometry, typename OutputIterator, typename Distance, typename Strategy > static inline void apply(Geometry const& geometry, OutputIterator& out, Distance const& max_distance, Strategy const& strategy) { dispatch::simplify_insert<Geometry>::apply(geometry, out, max_distance, strategy); } template <typename Geometry, typename OutputIterator, typename Distance> static inline void apply(Geometry const& geometry, OutputIterator& out, Distance const& max_distance, default_strategy) { typedef typename point_type<Geometry>::type point_type; typedef typename strategy::distance::services::default_strategy < point_tag, segment_tag, point_type >::type ds_strategy_type; typedef strategy::simplify::douglas_peucker < point_type, ds_strategy_type > strategy_type; BOOST_CONCEPT_ASSERT( (concepts::SimplifyStrategy<strategy_type, point_type>) ); apply(geometry, out, max_distance, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct simplify { template <typename Distance, typename Strategy> static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { resolve_strategy::simplify::apply(geometry, out, max_distance, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct simplify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Distance, typename Strategy> struct visitor: boost::static_visitor<void> { 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 <typename Geometry> void operator()(Geometry const& geometry, Geometry& out) const { simplify<Geometry>::apply(geometry, out, m_max_distance, m_strategy); } }; template <typename Distance, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& out, Distance const& max_distance, Strategy const& strategy) { boost::apply_visitor( visitor<Distance, Strategy>(max_distance, strategy), geometry, out ); } }; } // namespace resolve_variant /*! \brief Simplify a geometry using a specified strategy \ingroup simplify \tparam Geometry \tparam_geometry \tparam Distance A numerical distance measure \tparam Strategy A type fulfilling a SimplifyStrategy concept \param strategy A strategy to calculate simplification \param geometry input geometry, to be simplified \param out output geometry, simplified version of the input geometry \param max_distance distance (in units of input coordinates) of a vertex to other segments to be removed \param strategy simplify strategy to be used for simplification, might include point-distance strategy \image html svg_simplify_country.png "The image below presents the simplified country" \qbk{distinguish,with strategy} */ template<typename Geometry, typename Distance, typename Strategy> inline void simplify(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { concepts::check<Geometry>(); geometry::clear(out); resolve_variant::simplify<Geometry>::apply(geometry, out, max_distance, strategy); } /*! \brief Simplify a geometry \ingroup simplify \tparam Geometry \tparam_geometry \tparam Distance \tparam_numeric \note This version of simplify simplifies a geometry using the default strategy (Douglas Peucker), \param geometry input geometry, to be simplified \param out output geometry, simplified version of the input geometry \param max_distance distance (in units of input coordinates) of a vertex to other segments to be removed \qbk{[include reference/algorithms/simplify.qbk]} */ template<typename Geometry, typename Distance> inline void simplify(Geometry const& geometry, Geometry& out, Distance const& max_distance) { concepts::check<Geometry>(); geometry::simplify(geometry, out, max_distance, default_strategy()); } #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace simplify { /*! \brief Simplify a geometry, using an output iterator and a specified strategy \ingroup simplify \tparam Geometry \tparam_geometry \param geometry input geometry, to be simplified \param out output iterator, outputs all simplified points \param max_distance distance (in units of input coordinates) of a vertex to other segments to be removed \param strategy simplify strategy to be used for simplification, might include point-distance strategy \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/simplify.qbk]} */ template<typename Geometry, typename OutputIterator, typename Distance, typename Strategy> inline void simplify_insert(Geometry const& geometry, OutputIterator out, Distance const& max_distance, Strategy const& strategy) { concepts::check<Geometry const>(); resolve_strategy::simplify_insert::apply(geometry, out, max_distance, strategy); } /*! \brief Simplify a geometry, using an output iterator \ingroup simplify \tparam Geometry \tparam_geometry \param geometry input geometry, to be simplified \param out output iterator, outputs all simplified points \param max_distance distance (in units of input coordinates) of a vertex to other segments to be removed \qbk{[include reference/algorithms/simplify_insert.qbk]} */ template<typename Geometry, typename OutputIterator, typename Distance> inline void simplify_insert(Geometry const& geometry, OutputIterator out, Distance const& max_distance) { // Concept: output point type = point type of input geometry concepts::check<Geometry const>(); concepts::check<typename point_type<Geometry>::type>(); simplify_insert(geometry, out, max_distance, default_strategy()); } }} // namespace detail::simplify #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_SIMPLIFY_HPP detail/relate/de9im.hpp 0000644 00000025351 15125631656 0011022 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_DE9IM_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_DE9IM_HPP #include <tuple> #include <boost/geometry/algorithms/detail/relate/result.hpp> #include <boost/geometry/core/topological_dimension.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/util/sequence.hpp> #include <boost/geometry/util/tuples.hpp> namespace boost { namespace geometry { namespace de9im { /*! \brief DE-9IM model intersection matrix. \ingroup de9im \details This matrix can be used to express spatial relations as defined in Dimensionally Extended 9-Intersection Model. \qbk{[heading See also]} \qbk{* [link geometry.reference.algorithms.relation relation]} */ class matrix : public detail::relate::matrix<3, 3> { #ifdef DOXYGEN_INVOKED public: /*! \brief Initializes all of the matrix elements to F */ matrix(); /*! \brief Subscript operator \param index The index of the element \return The element */ char operator[](std::size_t index) const; /*! \brief Returns the iterator to the first element \return const RandomAccessIterator */ const_iterator begin() const; /*! \brief Returns the iterator past the last element \return const RandomAccessIterator */ const_iterator end() const; /*! \brief Returns the number of elements \return 9 */ static std::size_t size(); /*! \brief Returns raw pointer to elements \return const pointer to array of elements */ inline const char * data() const; /*! \brief Returns std::string containing elements \return string containing elements */ inline std::string str() const; #endif }; /*! \brief DE-9IM model intersection mask. \ingroup de9im \details This mask can be used to check spatial relations as defined in Dimensionally Extended 9-Intersection Model. \qbk{[heading See also]} \qbk{* [link geometry.reference.algorithms.relate relate]} */ class mask : public detail::relate::mask<3, 3> { typedef detail::relate::mask<3, 3> base_type; public: /*! \brief The constructor. \param code The mask pattern. */ inline explicit mask(const char* code) : base_type(code) {} /*! \brief The constructor. \param code The mask pattern. */ inline explicit mask(std::string const& code) : base_type(code.c_str(), code.size()) {} }; // static_mask /*! \brief DE-9IM model intersection mask (static version). \ingroup de9im \details This mask can be used to check spatial relations as defined in Dimensionally Extended 9-Intersection Model. \tparam II Interior/Interior intersection mask element \tparam IB Interior/Boundary intersection mask element \tparam IE Interior/Exterior intersection mask element \tparam BI Boundary/Interior intersection mask element \tparam BB Boundary/Boundary intersection mask element \tparam BE Boundary/Exterior intersection mask element \tparam EI Exterior/Interior intersection mask element \tparam EB Exterior/Boundary intersection mask element \tparam EE Exterior/Exterior intersection mask element \qbk{[heading See also]} \qbk{* [link geometry.reference.algorithms.relate relate]} */ template < char II = '*', char IB = '*', char IE = '*', char BI = '*', char BB = '*', char BE = '*', char EI = '*', char EB = '*', char EE = '*' > class static_mask : public detail::relate::static_mask < std::integer_sequence < char, II, IB, IE, BI, BB, BE, EI, EB, EE >, 3, 3 > {}; inline std::tuple<mask, mask> operator||(mask const& m1, mask const& m2) { return std::tuple<mask, mask>(m1, m2); } template <typename ...Masks> inline std::tuple<Masks..., mask> operator||(std::tuple<Masks...> const& t, mask const& m) { return geometry::tuples::push_back < std::tuple<Masks...>, mask >::apply(t, m); } template < char II1, char IB1, char IE1, char BI1, char BB1, char BE1, char EI1, char EB1, char EE1, char II2, char IB2, char IE2, char BI2, char BB2, char BE2, char EI2, char EB2, char EE2 > inline util::type_sequence < static_mask<II1, IB1, IE1, BI1, BB1, BE1, EI1, EB1, EE1>, static_mask<II2, IB2, IE2, BI2, BB2, BE2, EI2, EB2, EE2> > operator||(static_mask<II1, IB1, IE1, BI1, BB1, BE1, EI1, EB1, EE1> const& , static_mask<II2, IB2, IE2, BI2, BB2, BE2, EI2, EB2, EE2> const& ) { return util::type_sequence < static_mask<II1, IB1, IE1, BI1, BB1, BE1, EI1, EB1, EE1>, static_mask<II2, IB2, IE2, BI2, BB2, BE2, EI2, EB2, EE2> >(); } template < typename ...StaticMasks, char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE > inline util::type_sequence < StaticMasks..., static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> > operator||(util::type_sequence<StaticMasks...> const& , static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> const& ) { return util::type_sequence < StaticMasks..., static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> >(); } } // namespace de9im #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace de9im { // PREDEFINED MASKS // TODO: // 1. specialize for simplified masks if available // e.g. for TOUCHES use 1 mask for A/A // 2. Think about dimensions > 2 e.g. should TOUCHES be true // if the interior of the Areal overlaps the boundary of the Volumetric // like it's true for Linear/Areal // EQUALS template <typename Geometry1, typename Geometry2> struct static_mask_equals_type { typedef geometry::de9im::static_mask<'T', '*', 'F', '*', '*', 'F', 'F', 'F', '*'> type; // wikipedia //typedef geometry::de9im::static_mask<'T', 'F', 'F', 'F', 'T', 'F', 'F', 'F', 'T'> type; // OGC }; // DISJOINT template <typename Geometry1, typename Geometry2> struct static_mask_disjoint_type { typedef geometry::de9im::static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> type; }; // TOUCHES - NOT P/P template < typename Geometry1, typename Geometry2, std::size_t Dim1 = geometry::topological_dimension<Geometry1>::value, std::size_t Dim2 = geometry::topological_dimension<Geometry2>::value > struct static_mask_touches_impl { typedef util::type_sequence < geometry::de9im::static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>, geometry::de9im::static_mask<'F', '*', '*', 'T', '*', '*', '*', '*', '*'>, geometry::de9im::static_mask<'F', '*', '*', '*', 'T', '*', '*', '*', '*'> > type; }; // According to OGC, doesn't apply to P/P // Using the above mask the result would be always false template <typename Geometry1, typename Geometry2> struct static_mask_touches_impl<Geometry1, Geometry2, 0, 0> { typedef geometry::detail::relate::false_mask type; }; template <typename Geometry1, typename Geometry2> struct static_mask_touches_type : static_mask_touches_impl<Geometry1, Geometry2> {}; // WITHIN template <typename Geometry1, typename Geometry2> struct static_mask_within_type { typedef geometry::de9im::static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> type; }; // COVERED_BY (non OGC) template <typename Geometry1, typename Geometry2> struct static_mask_covered_by_type { typedef util::type_sequence < geometry::de9im::static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'>, geometry::de9im::static_mask<'*', 'T', 'F', '*', '*', 'F', '*', '*', '*'>, geometry::de9im::static_mask<'*', '*', 'F', 'T', '*', 'F', '*', '*', '*'>, geometry::de9im::static_mask<'*', '*', 'F', '*', 'T', 'F', '*', '*', '*'> > type; }; // CROSSES // dim(G1) < dim(G2) - P/L P/A L/A template < typename Geometry1, typename Geometry2, std::size_t Dim1 = geometry::topological_dimension<Geometry1>::value, std::size_t Dim2 = geometry::topological_dimension<Geometry2>::value, bool D1LessD2 = (Dim1 < Dim2) > struct static_mask_crosses_impl { typedef geometry::de9im::static_mask<'T', '*', 'T', '*', '*', '*', '*', '*', '*'> type; }; // TODO: I'm not sure if this one below should be available! // dim(G1) > dim(G2) - L/P A/P A/L template < typename Geometry1, typename Geometry2, std::size_t Dim1, std::size_t Dim2 > struct static_mask_crosses_impl<Geometry1, Geometry2, Dim1, Dim2, false> { typedef geometry::de9im::static_mask<'T', '*', '*', '*', '*', '*', 'T', '*', '*'> type; }; // dim(G1) == dim(G2) - P/P A/A template < typename Geometry1, typename Geometry2, std::size_t Dim > struct static_mask_crosses_impl<Geometry1, Geometry2, Dim, Dim, false> { typedef geometry::detail::relate::false_mask type; }; // dim(G1) == 1 && dim(G2) == 1 - L/L template <typename Geometry1, typename Geometry2> struct static_mask_crosses_impl<Geometry1, Geometry2, 1, 1, false> { typedef geometry::de9im::static_mask<'0', '*', '*', '*', '*', '*', '*', '*', '*'> type; }; template <typename Geometry1, typename Geometry2> struct static_mask_crosses_type : static_mask_crosses_impl<Geometry1, Geometry2> {}; // OVERLAPS // dim(G1) != dim(G2) - NOT P/P, L/L, A/A template < typename Geometry1, typename Geometry2, std::size_t Dim1 = geometry::topological_dimension<Geometry1>::value, std::size_t Dim2 = geometry::topological_dimension<Geometry2>::value > struct static_mask_overlaps_impl { typedef geometry::detail::relate::false_mask type; }; // dim(G1) == D && dim(G2) == D - P/P A/A template <typename Geometry1, typename Geometry2, std::size_t Dim> struct static_mask_overlaps_impl<Geometry1, Geometry2, Dim, Dim> { typedef geometry::de9im::static_mask<'T', '*', 'T', '*', '*', '*', 'T', '*', '*'> type; }; // dim(G1) == 1 && dim(G2) == 1 - L/L template <typename Geometry1, typename Geometry2> struct static_mask_overlaps_impl<Geometry1, Geometry2, 1, 1> { typedef geometry::de9im::static_mask<'1', '*', 'T', '*', '*', '*', 'T', '*', '*'> type; }; template <typename Geometry1, typename Geometry2> struct static_mask_overlaps_type : static_mask_overlaps_impl<Geometry1, Geometry2> {}; }} // namespace detail::de9im #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_DE9IM_HPP detail/relate/boundary_checker.hpp 0000644 00000013703 15125631656 0013320 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/util/has_nan_coordinate.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { enum boundary_query { boundary_front, boundary_back, boundary_any }; template <typename Geometry, typename WithinStrategy, // Point/Point equals (within) strategy typename Tag = typename geometry::tag<Geometry>::type> class boundary_checker {}; template <typename Geometry, typename WithinStrategy> class boundary_checker<Geometry, WithinStrategy, linestring_tag> { typedef typename point_type<Geometry>::type point_type; public: typedef WithinStrategy equals_strategy_type; boundary_checker(Geometry const& g) : has_boundary( boost::size(g) >= 2 && !detail::equals::equals_point_point(range::front(g), range::back(g), equals_strategy_type()) ) #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER , geometry(g) #endif {} template <boundary_query BoundaryQuery> bool is_endpoint_boundary(point_type const& pt) const { boost::ignore_unused(pt); #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER // may give false positives for INT BOOST_GEOMETRY_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) && detail::equals::equals_point_point(pt, range::front(geometry), WithinStrategy()) || (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) && detail::equals::equals_point_point(pt, range::back(geometry), WithinStrategy()) ); #endif return has_boundary; } private: bool has_boundary; #ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER Geometry const& geometry; #endif }; template <typename Geometry, typename WithinStrategy> class boundary_checker<Geometry, WithinStrategy, multi_linestring_tag> { typedef typename point_type<Geometry>::type point_type; public: typedef WithinStrategy equals_strategy_type; boundary_checker(Geometry const& g) : is_filled(false), geometry(g) {} // First call O(NlogN) // Each next call O(logN) template <boundary_query BoundaryQuery> bool is_endpoint_boundary(point_type const& pt) const { typedef geometry::less<point_type, -1, typename WithinStrategy::cs_tag> less_type; typedef typename boost::range_size<Geometry>::type size_type; size_type multi_count = boost::size(geometry); if ( multi_count < 1 ) return false; if ( ! is_filled ) { //boundary_points.clear(); boundary_points.reserve(multi_count * 2); typedef typename boost::range_iterator<Geometry const>::type multi_iterator; for ( multi_iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++ it ) { typename boost::range_reference<Geometry const>::type ls = *it; // empty or point - no boundary if (boost::size(ls) < 2) { continue; } typedef typename boost::range_reference < typename boost::range_value<Geometry const>::type const >::type point_reference; point_reference front_pt = range::front(ls); point_reference back_pt = range::back(ls); // linear ring or point - no boundary if (! equals::equals_point_point(front_pt, back_pt, equals_strategy_type())) { // do not add points containing NaN coordinates // because they cannot be reasonably compared, e.g. with MSVC // an assertion failure is reported in std::equal_range() if (! geometry::has_nan_coordinate(front_pt)) { boundary_points.push_back(front_pt); } if (! geometry::has_nan_coordinate(back_pt)) { boundary_points.push_back(back_pt); } } } std::sort(boundary_points.begin(), boundary_points.end(), less_type()); is_filled = true; } std::size_t equal_points_count = boost::size( std::equal_range(boundary_points.begin(), boundary_points.end(), pt, less_type()) ); return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0 } private: mutable bool is_filled; // TODO: store references/pointers instead of points? mutable std::vector<point_type> boundary_points; Geometry const& geometry; }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP detail/relate/follow_helpers.hpp 0000644 00000032072 15125631656 0013035 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP #include <vector> #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // NOTE: This iterates through single geometries for which turns were not generated. // It doesn't mean that the geometry is disjoint, only that no turns were detected. template <std::size_t OpId, typename Geometry, typename Tag = typename geometry::tag<Geometry>::type, bool IsMulti = boost::is_base_of<multi_tag, Tag>::value > struct for_each_disjoint_geometry_if : public not_implemented<Tag> {}; template <std::size_t OpId, typename Geometry, typename Tag> struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, false> { template <typename TurnIt, typename Pred> static inline bool apply(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred) { if ( first != last ) return false; pred(geometry); return true; } }; template <std::size_t OpId, typename Geometry, typename Tag> struct for_each_disjoint_geometry_if<OpId, Geometry, Tag, true> { template <typename TurnIt, typename Pred> static inline bool apply(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred) { if ( first != last ) return for_turns(first, last, geometry, pred); else return for_empty(geometry, pred); } template <typename Pred> static inline bool for_empty(Geometry const& geometry, Pred & pred) { typedef typename boost::range_iterator<Geometry const>::type iterator; // O(N) // check predicate for each contained geometry without generated turn for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) { bool cont = pred(*it); if ( !cont ) break; } return !boost::empty(geometry); } template <typename TurnIt, typename Pred> static inline bool for_turns(TurnIt first, TurnIt last, Geometry const& geometry, Pred & pred) { BOOST_GEOMETRY_ASSERT(first != last); const std::size_t count = boost::size(geometry); boost::ignore_unused(count); // O(I) // gather info about turns generated for contained geometries std::vector<bool> detected_intersections(count, false); for ( TurnIt it = first ; it != last ; ++it ) { signed_size_type multi_index = it->operations[OpId].seg_id.multi_index; BOOST_GEOMETRY_ASSERT(multi_index >= 0); std::size_t const index = static_cast<std::size_t>(multi_index); BOOST_GEOMETRY_ASSERT(index < count); detected_intersections[index] = true; } bool found = false; // O(N) // check predicate for each contained geometry without generated turn for ( std::vector<bool>::iterator it = detected_intersections.begin() ; it != detected_intersections.end() ; ++it ) { // if there were no intersections for this multi_index if ( *it == false ) { found = true; std::size_t const index = std::size_t(std::distance(detected_intersections.begin(), it)); bool cont = pred(range::at(geometry, index)); if ( !cont ) break; } } return found; } }; // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! template <typename Point> class point_info { public: point_info() : sid_ptr(NULL), pt_ptr(NULL) {} point_info(Point const& pt, segment_identifier const& sid) : sid_ptr(boost::addressof(sid)) , pt_ptr(boost::addressof(pt)) {} segment_identifier const& seg_id() const { BOOST_GEOMETRY_ASSERT(sid_ptr); return *sid_ptr; } Point const& point() const { BOOST_GEOMETRY_ASSERT(pt_ptr); return *pt_ptr; } //friend bool operator==(point_identifier const& l, point_identifier const& r) //{ // return l.seg_id() == r.seg_id() // && detail::equals::equals_point_point(l.point(), r.point()); //} private: const segment_identifier * sid_ptr; const Point * pt_ptr; }; // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! class same_single { public: same_single(segment_identifier const& sid) : sid_ptr(boost::addressof(sid)) {} bool operator()(segment_identifier const& sid) const { return sid.multi_index == sid_ptr->multi_index; } template <typename Point> bool operator()(point_info<Point> const& pid) const { return operator()(pid.seg_id()); } private: const segment_identifier * sid_ptr; }; class same_ring { public: same_ring(segment_identifier const& sid) : sid_ptr(boost::addressof(sid)) {} bool operator()(segment_identifier const& sid) const { return sid.multi_index == sid_ptr->multi_index && sid.ring_index == sid_ptr->ring_index; } private: const segment_identifier * sid_ptr; }; // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! template <typename SameRange = same_single> class segment_watcher { public: segment_watcher() : m_seg_id_ptr(NULL) {} bool update(segment_identifier const& seg_id) { bool result = m_seg_id_ptr == 0 || !SameRange(*m_seg_id_ptr)(seg_id); m_seg_id_ptr = boost::addressof(seg_id); return result; } private: const segment_identifier * m_seg_id_ptr; }; // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! template <typename TurnInfo, std::size_t OpId> class exit_watcher { static const std::size_t op_id = OpId; static const std::size_t other_op_id = (OpId + 1) % 2; typedef typename TurnInfo::point_type point_type; typedef detail::relate::point_info<point_type> point_info; public: exit_watcher() : m_exit_operation(overlay::operation_none) , m_exit_turn_ptr(NULL) {} void enter(TurnInfo const& turn) { m_other_entry_points.push_back( point_info(turn.point, turn.operations[other_op_id].seg_id) ); } // TODO: exit_per_geometry parameter looks not very safe // wrong value may be easily passed void exit(TurnInfo const& turn, bool exit_per_geometry = true) { //segment_identifier const& seg_id = turn.operations[op_id].seg_id; segment_identifier const& other_id = turn.operations[other_op_id].seg_id; overlay::operation_type exit_op = turn.operations[op_id].operation; typedef typename std::vector<point_info>::iterator point_iterator; // search for the entry point in the same range of other geometry point_iterator entry_it = std::find_if(m_other_entry_points.begin(), m_other_entry_points.end(), same_single(other_id)); // this end point has corresponding entry point if ( entry_it != m_other_entry_points.end() ) { // erase the corresponding entry point m_other_entry_points.erase(entry_it); if ( exit_per_geometry || m_other_entry_points.empty() ) { // here we know that we possibly left LS // we must still check if we didn't get back on the same point m_exit_operation = exit_op; m_exit_turn_ptr = boost::addressof(turn); } } } bool is_outside() const { // if we didn't entered anything in the past, we're outside return m_other_entry_points.empty(); } bool is_outside(TurnInfo const& turn) const { return m_other_entry_points.empty() || std::find_if(m_other_entry_points.begin(), m_other_entry_points.end(), same_single( turn.operations[other_op_id].seg_id)) == m_other_entry_points.end(); } overlay::operation_type get_exit_operation() const { return m_exit_operation; } point_type const& get_exit_point() const { BOOST_GEOMETRY_ASSERT(m_exit_operation != overlay::operation_none); BOOST_GEOMETRY_ASSERT(m_exit_turn_ptr); return m_exit_turn_ptr->point; } TurnInfo const& get_exit_turn() const { BOOST_GEOMETRY_ASSERT(m_exit_operation != overlay::operation_none); BOOST_GEOMETRY_ASSERT(m_exit_turn_ptr); return *m_exit_turn_ptr; } void reset_detected_exit() { m_exit_operation = overlay::operation_none; } void reset() { m_exit_operation = overlay::operation_none; m_other_entry_points.clear(); } private: overlay::operation_type m_exit_operation; const TurnInfo * m_exit_turn_ptr; std::vector<point_info> m_other_entry_points; // TODO: use map here or sorted vector? }; template <std::size_t OpId, typename Turn, typename EqPPStrategy> inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn, EqPPStrategy const& strategy) { segment_identifier const& prev_seg_id = prev_turn.operations[OpId].seg_id; segment_identifier const& curr_seg_id = curr_turn.operations[OpId].seg_id; if ( prev_seg_id.multi_index != curr_seg_id.multi_index || prev_seg_id.ring_index != curr_seg_id.ring_index ) { return false; } // TODO: will this work if between segments there will be some number of degenerated ones? if ( prev_seg_id.segment_index != curr_seg_id.segment_index && ( ! curr_turn.operations[OpId].fraction.is_zero() || prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) ) { return false; } return detail::equals::equals_point_point(prev_turn.point, curr_turn.point, strategy); } template <boundary_query BoundaryQuery, typename Point, typename BoundaryChecker> static inline bool is_endpoint_on_boundary(Point const& pt, BoundaryChecker & boundary_checker) { return boundary_checker.template is_endpoint_boundary<BoundaryQuery>(pt); } template <boundary_query BoundaryQuery, typename IntersectionPoint, typename OperationInfo, typename BoundaryChecker> static inline bool is_ip_on_boundary(IntersectionPoint const& ip, OperationInfo const& operation_info, BoundaryChecker & boundary_checker, segment_identifier const& seg_id) { boost::ignore_unused(seg_id); bool res = false; // IP on the last point of the linestring if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) && operation_info.position == overlay::position_back ) { // check if this point is a boundary res = boundary_checker.template is_endpoint_boundary<boundary_back>(ip); } // IP on the last point of the linestring else if ( BOOST_GEOMETRY_CONDITION(BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) && operation_info.position == overlay::position_front ) { // check if this point is a boundary res = boundary_checker.template is_endpoint_boundary<boundary_front>(ip); } return res; } }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_FOLLOW_HELPERS_HPP detail/relate/point_geometry.hpp 0000644 00000015540 15125631656 0013056 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> //#include <boost/geometry/algorithms/within.hpp> //#include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/relate/result.hpp> #include <boost/geometry/algorithms/detail/relate/topology_check.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // non-point geometry template <typename Point, typename Geometry, bool Transpose = false> struct point_geometry { // TODO: interrupt only if the topology check is complex static const bool interruption_enabled = true; template <typename Result, typename Strategy> static inline void apply(Point const& point, Geometry const& geometry, Result & result, Strategy const& strategy) { int pig = detail::within::point_in_geometry(point, geometry, strategy); if ( pig > 0 ) // within { relate::set<interior, interior, '0', Transpose>(result); } else if ( pig == 0 ) { relate::set<interior, boundary, '0', Transpose>(result); } else // pig < 0 - not within { relate::set<interior, exterior, '0', Transpose>(result); } relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; typedef detail::relate::topology_check < Geometry, typename Strategy::equals_point_point_strategy_type > tc_t; if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) ) { // the point is on the boundary if ( pig == 0 ) { // NOTE: even for MLs, if there is at least one boundary point, // somewhere there must be another one relate::set<exterior, interior, tc_t::interior, Transpose>(result); relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); } else { // check if there is a boundary in Geometry tc_t tc(geometry); if ( tc.has_interior() ) relate::set<exterior, interior, tc_t::interior, Transpose>(result); if ( tc.has_boundary() ) relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); } } } }; // transposed result of point_geometry template <typename Geometry, typename Point> struct geometry_point { // TODO: interrupt only if the topology check is complex static const bool interruption_enabled = true; template <typename Result, typename Strategy> static inline void apply(Geometry const& geometry, Point const& point, Result & result, Strategy const& strategy) { point_geometry<Point, Geometry, true>::apply(point, geometry, result, strategy); } }; // TODO: rewrite the folowing: //// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box) //// There is no EPS used in those functions, values are compared using < or <= //// so comparing MIN and MAX in the same way should be fine // //template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value> //struct box_has_interior //{ // static inline bool apply(Box const& box) // { // return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box) // && box_has_interior<Box, I + 1, D>::apply(box); // } //}; // //template <typename Box, std::size_t D> //struct box_has_interior<Box, D, D> //{ // static inline bool apply(Box const&) { return true; } //}; // //// NOTE: especially important here (see the NOTE above). // //template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value> //struct box_has_equal_min_max //{ // static inline bool apply(Box const& box) // { // return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box) // && box_has_equal_min_max<Box, I + 1, D>::apply(box); // } //}; // //template <typename Box, std::size_t D> //struct box_has_equal_min_max<Box, D, D> //{ // static inline bool apply(Box const&) { return true; } //}; // //template <typename Point, typename Box> //struct point_box //{ // static inline result apply(Point const& point, Box const& box) // { // result res; // // if ( geometry::within(point, box) ) // this also means that the box has interior // { // return result("0FFFFFTTT"); // } // else if ( geometry::covered_by(point, box) ) // point is on the boundary // { // //if ( box_has_interior<Box>::apply(box) ) // //{ // // return result("F0FFFFTTT"); // //} // //else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point // //{ // // return result("F0FFFFFFT"); // //} // //else // no interior outside point // //{ // // return result("F0FFFFFTT"); // //} // return result("F0FFFF**T"); // } // else // { // /*if ( box_has_interior<Box>::apply(box) ) // { // return result("FF0FFFTTT"); // } // else // { // return result("FF0FFFFTT"); // }*/ // return result("FF0FFF*TT"); // } // // return res; // } //}; // //template <typename Box, typename Point> //struct box_point //{ // static inline result apply(Box const& box, Point const& point) // { // if ( geometry::within(point, box) ) // return result("0FTFFTFFT"); // else if ( geometry::covered_by(point, box) ) // return result("FF*0F*FFT"); // else // return result("FF*FFT0FT"); // } //}; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_GEOMETRY_HPP detail/relate/linear_areal.hpp 0000644 00000174260 15125631656 0012435 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP #include <boost/core/ignore_unused.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/topological_dimension.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/util/type_traits.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/detail/single_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/turns.hpp> #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // WARNING! // TODO: In the worst case calling this Pred in a loop for MultiLinestring/MultiPolygon may take O(NM) // Use the rtree in this case! // may be used to set IE and BE for a Linear geometry for which no turns were generated template < typename Geometry2, typename Result, typename PointInArealStrategy, typename BoundaryChecker, bool TransposeResult > class no_turns_la_linestring_pred { public: no_turns_la_linestring_pred(Geometry2 const& geometry2, Result & res, PointInArealStrategy const& point_in_areal_strategy, BoundaryChecker const& boundary_checker) : m_geometry2(geometry2) , m_result(res) , m_point_in_areal_strategy(point_in_areal_strategy) , m_boundary_checker(boundary_checker) , m_interrupt_flags(0) { if ( ! may_update<interior, interior, '1', TransposeResult>(m_result) ) { m_interrupt_flags |= 1; } if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) ) { m_interrupt_flags |= 2; } if ( ! may_update<boundary, interior, '0', TransposeResult>(m_result) ) { m_interrupt_flags |= 4; } if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) ) { m_interrupt_flags |= 8; } } template <typename Linestring> bool operator()(Linestring const& linestring) { std::size_t const count = boost::size(linestring); // invalid input if ( count < 2 ) { // ignore // TODO: throw an exception? return true; } // if those flags are set nothing will change if ( m_interrupt_flags == 0xF ) { return false; } int const pig = detail::within::point_in_geometry(range::front(linestring), m_geometry2, m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT_MSG(pig != 0, "There should be no IPs"); if ( pig > 0 ) { update<interior, interior, '1', TransposeResult>(m_result); m_interrupt_flags |= 1; } else { update<interior, exterior, '1', TransposeResult>(m_result); m_interrupt_flags |= 2; } // check if there is a boundary if ( ( m_interrupt_flags & 0xC ) != 0xC // if wasn't already set && ( m_boundary_checker.template is_endpoint_boundary<boundary_front>(range::front(linestring)) || m_boundary_checker.template is_endpoint_boundary<boundary_back>(range::back(linestring)) ) ) { if ( pig > 0 ) { update<boundary, interior, '0', TransposeResult>(m_result); m_interrupt_flags |= 4; } else { update<boundary, exterior, '0', TransposeResult>(m_result); m_interrupt_flags |= 8; } } return m_interrupt_flags != 0xF && ! m_result.interrupt; } private: Geometry2 const& m_geometry2; Result & m_result; PointInArealStrategy const& m_point_in_areal_strategy; BoundaryChecker const& m_boundary_checker; unsigned m_interrupt_flags; }; // may be used to set EI and EB for an Areal geometry for which no turns were generated template <typename Result, bool TransposeResult> class no_turns_la_areal_pred { public: no_turns_la_areal_pred(Result & res) : m_result(res) , interrupt(! may_update<interior, exterior, '2', TransposeResult>(m_result) && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) ) {} template <typename Areal> bool operator()(Areal const& areal) { if ( interrupt ) { return false; } // TODO: // handle empty/invalid geometries in a different way than below? typedef typename geometry::point_type<Areal>::type point_type; point_type dummy; bool const ok = boost::geometry::point_on_border(dummy, areal); // TODO: for now ignore, later throw an exception? if ( !ok ) { return true; } update<interior, exterior, '2', TransposeResult>(m_result); update<boundary, exterior, '1', TransposeResult>(m_result); return false; } private: Result & m_result; bool const interrupt; }; // The implementation of an algorithm calculating relate() for L/A template <typename Geometry1, typename Geometry2, bool TransposeResult = false> struct linear_areal { // check Linear / Areal BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 1 && topological_dimension<Geometry2>::value == 2); static const bool interruption_enabled = true; typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; template <typename Geom1, typename Geom2, typename Strategy> struct multi_turn_info : turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type { multi_turn_info() : priority(0) {} int priority; // single-geometry sorting priority }; template <typename Geom1, typename Geom2, typename Strategy> struct turn_info_type : std::conditional < util::is_multi<Geometry2>::value, multi_turn_info<Geom1, Geom2, Strategy>, typename turns::get_turns<Geom1, Geom2>::template turn_info_type<Strategy>::type > {}; template <typename Result, typename IntersectionStrategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, IntersectionStrategy const& intersection_strategy) { // TODO: If Areal geometry may have infinite size, change the following line: // The result should be FFFFFFFFF relate::set<exterior, exterior, result_dimension<Geometry2>::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; // get and analyse turns typedef typename turn_info_type<Geometry1, Geometry2, IntersectionStrategy>::type turn_type; std::vector<turn_type> turns; interrupt_policy_linear_areal<Geometry2, Result> interrupt_policy(geometry2, result); turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; typedef typename IntersectionStrategy::template point_in_geometry_strategy<Geometry1, Geometry2>::type within_strategy_type; within_strategy_type const within_strategy = intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(); typedef typename IntersectionStrategy::cs_tag cs_tag; typedef typename within_strategy_type::equals_point_point_strategy_type eq_pp_strategy_type; typedef boundary_checker < Geometry1, eq_pp_strategy_type > boundary_checker1_type; boundary_checker1_type boundary_checker1(geometry1); no_turns_la_linestring_pred < Geometry2, Result, within_strategy_type, boundary_checker1_type, TransposeResult > pred1(geometry2, result, within_strategy, boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; no_turns_la_areal_pred<Result, !TransposeResult> pred2(result); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; if ( turns.empty() ) return; // This is set here because in the case if empty Areal geometry were passed // those shouldn't be set relate::set<exterior, interior, '2', TransposeResult>(result);// FFFFFF2Fd if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; { sort_dispatch<cs_tag>(turns.begin(), turns.end(), util::is_multi<Geometry2>()); turns_analyser<turn_type> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end(), geometry1, geometry2, boundary_checker1, intersection_strategy.get_side_strategy()); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; } // If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings if ( !interrupt_policy.is_boundary_found ) { relate::set<exterior, boundary, '1', TransposeResult>(result); } // Don't calculate it if it's required else if ( may_update<exterior, boundary, '1', TransposeResult>(result) ) { // TODO: REVISE THIS CODE AND PROBABLY REWRITE SOME PARTS TO BE MORE HUMAN-READABLE // IN GENERAL IT ANALYSES THE RINGS OF AREAL GEOMETRY AND DETECTS THE ONES THAT // MAY OVERLAP THE INTERIOR OF LINEAR GEOMETRY (NO IPs OR NON-FAKE 'u' OPERATION) // NOTE: For one case std::sort may be called again to sort data by operations for data already sorted by ring index // In the worst case scenario the complexity will be O( NlogN + R*(N/R)log(N/R) ) // So always should remain O(NlogN) -> for R==1 <-> 1(N/1)log(N/1), for R==N <-> N(N/N)log(N/N) // Some benchmarking should probably be done to check if only one std::sort should be used // sort by multi_index and rind_index std::sort(turns.begin(), turns.end(), less_ring()); typedef typename std::vector<turn_type>::iterator turn_iterator; turn_iterator it = turns.begin(); segment_identifier * prev_seg_id_ptr = NULL; // for each ring for ( ; it != turns.end() ; ) { // it's the next single geometry if ( prev_seg_id_ptr == NULL || prev_seg_id_ptr->multi_index != it->operations[1].seg_id.multi_index ) { // if the first ring has no IPs if ( it->operations[1].seg_id.ring_index > -1 ) { // we can be sure that the exterior overlaps the boundary relate::set<exterior, boundary, '1', TransposeResult>(result); break; } // if there was some previous ring if ( prev_seg_id_ptr != NULL ) { signed_size_type const next_ring_index = prev_seg_id_ptr->ring_index + 1; BOOST_GEOMETRY_ASSERT(next_ring_index >= 0); // if one of the last rings of previous single geometry was ommited if ( static_cast<std::size_t>(next_ring_index) < geometry::num_interior_rings( single_geometry(geometry2, *prev_seg_id_ptr)) ) { // we can be sure that the exterior overlaps the boundary relate::set<exterior, boundary, '1', TransposeResult>(result); break; } } } // if it's the same single geometry else /*if ( previous_multi_index == it->operations[1].seg_id.multi_index )*/ { // and we jumped over one of the rings if ( prev_seg_id_ptr != NULL // just in case && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index ) { // we can be sure that the exterior overlaps the boundary relate::set<exterior, boundary, '1', TransposeResult>(result); break; } } prev_seg_id_ptr = boost::addressof(it->operations[1].seg_id); // find the next ring first iterator and check if the analysis should be performed has_boundary_intersection has_boundary_inters; turn_iterator next = find_next_ring(it, turns.end(), has_boundary_inters); // if there is no 1d overlap with the boundary if ( !has_boundary_inters.result ) { // we can be sure that the exterior overlaps the boundary relate::set<exterior, boundary, '1', TransposeResult>(result); break; } // else there is 1d overlap with the boundary so we must analyse the boundary else { // u, c typedef turns::less<1, turns::less_op_areal_linear<1>, cs_tag> less; std::sort(it, next, less()); eq_pp_strategy_type const eq_pp_strategy = within_strategy.get_equals_point_point_strategy(); // analyse areal_boundary_analyser<turn_type> analyser; for ( turn_iterator rit = it ; rit != next ; ++rit ) { // if the analyser requests, break the search if ( !analyser.apply(it, rit, next, eq_pp_strategy) ) break; } // if the boundary of Areal goes out of the Linear if ( analyser.is_union_detected ) { // we can be sure that the boundary of Areal overlaps the exterior of Linear relate::set<exterior, boundary, '1', TransposeResult>(result); break; } } it = next; } // if there was some previous ring if ( prev_seg_id_ptr != NULL ) { signed_size_type const next_ring_index = prev_seg_id_ptr->ring_index + 1; BOOST_GEOMETRY_ASSERT(next_ring_index >= 0); // if one of the last rings of previous single geometry was ommited if ( static_cast<std::size_t>(next_ring_index) < geometry::num_interior_rings( single_geometry(geometry2, *prev_seg_id_ptr)) ) { // we can be sure that the exterior overlaps the boundary relate::set<exterior, boundary, '1', TransposeResult>(result); } } } } template <typename It, typename Pred, typename Comp> static void for_each_equal_range(It first, It last, Pred pred, Comp comp) { if ( first == last ) return; It first_equal = first; It prev = first; for ( ++first ; ; ++first, ++prev ) { if ( first == last || !comp(*prev, *first) ) { pred(first_equal, first); first_equal = first; } if ( first == last ) break; } } struct same_ip { template <typename Turn> bool operator()(Turn const& left, Turn const& right) const { return left.operations[0].seg_id == right.operations[0].seg_id && left.operations[0].fraction == right.operations[0].fraction; } }; struct same_ip_and_multi_index { template <typename Turn> bool operator()(Turn const& left, Turn const& right) const { return same_ip()(left, right) && left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index; } }; template <typename OpToPriority> struct set_turns_group_priority { template <typename TurnIt> void operator()(TurnIt first, TurnIt last) const { BOOST_GEOMETRY_ASSERT(first != last); static OpToPriority op_to_priority; // find the operation with the least priority int least_priority = op_to_priority(first->operations[0]); for ( TurnIt it = first + 1 ; it != last ; ++it ) { int priority = op_to_priority(it->operations[0]); if ( priority < least_priority ) least_priority = priority; } // set the least priority for all turns of the group for ( TurnIt it = first ; it != last ; ++it ) { it->priority = least_priority; } } }; template <typename SingleLess> struct sort_turns_group { struct less { template <typename Turn> bool operator()(Turn const& left, Turn const& right) const { return left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index ? SingleLess()(left, right) : left.priority < right.priority; } }; template <typename TurnIt> void operator()(TurnIt first, TurnIt last) const { std::sort(first, last, less()); } }; template <typename CSTag, typename TurnIt> static void sort_dispatch(TurnIt first, TurnIt last, std::true_type const& /*is_multi*/) { // sort turns by Linear seg_id, then by fraction, then by other multi_index typedef turns::less<0, turns::less_other_multi_index<0>, CSTag> less; std::sort(first, last, less()); // For the same IP and multi_index - the same other's single geometry // set priorities as the least operation found for the whole single geometry // so e.g. single geometries containing 'u' will always be before those only containing 'i' typedef turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic; for_each_equal_range(first, last, set_turns_group_priority<op_to_int_xuic>(), // least operation in xuic order same_ip_and_multi_index()); // other's multi_index // When priorities for single geometries are set now sort turns for the same IP // if multi_index is the same sort them according to the single-less // else use priority of the whole single-geometry set earlier typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> single_less; for_each_equal_range(first, last, sort_turns_group<single_less>(), same_ip()); } template <typename CSTag, typename TurnIt> static void sort_dispatch(TurnIt first, TurnIt last, std::false_type const& /*is_multi*/) { // sort turns by Linear seg_id, then by fraction, then // for same ring id: x, u, i, c // for different ring id: c, i, u, x typedef turns::less<0, turns::less_op_linear_areal_single<0>, CSTag> less; std::sort(first, last, less()); } // interrupt policy which may be passed to get_turns to interrupt the analysis // based on the info in the passed result/mask template <typename Areal, typename Result> class interrupt_policy_linear_areal { public: static bool const enabled = true; interrupt_policy_linear_areal(Areal const& areal, Result & result) : m_result(result), m_areal(areal) , is_boundary_found(false) {} // TODO: since we update result for some operations here, we may not do it in the analyser! template <typename Range> inline bool apply(Range const& turns) { typedef typename boost::range_iterator<Range const>::type iterator; for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) { if ( it->operations[0].operation == overlay::operation_intersection ) { bool const no_interior_rings = geometry::num_interior_rings( single_geometry(m_areal, it->operations[1].seg_id)) == 0; // WARNING! THIS IS TRUE ONLY IF THE POLYGON IS SIMPLE! // OR WITHOUT INTERIOR RINGS (AND OF COURSE VALID) if ( no_interior_rings ) update<interior, interior, '1', TransposeResult>(m_result); } else if ( it->operations[0].operation == overlay::operation_continue ) { update<interior, boundary, '1', TransposeResult>(m_result); is_boundary_found = true; } else if ( ( it->operations[0].operation == overlay::operation_union || it->operations[0].operation == overlay::operation_blocked ) && it->operations[0].position == overlay::position_middle ) { // TODO: here we could also check the boundaries and set BB at this point update<interior, boundary, '0', TransposeResult>(m_result); } } return m_result.interrupt; } private: Result & m_result; Areal const& m_areal; public: bool is_boundary_found; }; // This analyser should be used like Input or SinglePass Iterator // IMPORTANT! It should be called also for the end iterator - last template <typename TurnInfo> class turns_analyser { typedef typename TurnInfo::point_type turn_point_type; static const std::size_t op_id = 0; static const std::size_t other_op_id = 1; template <typename TurnPointCSTag, typename PointP, typename PointQ, typename SideStrategy, typename Pi = PointP, typename Pj = PointP, typename Pk = PointP, typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ > struct la_side_calculator { inline la_side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, Qi const& qi, Qj const& qj, Qk const& qk, SideStrategy const& side_strategy) : m_pi(pi), m_pj(pj), m_pk(pk) , m_qi(qi), m_qj(qj), m_qk(qk) , m_side_strategy(side_strategy) {} inline int pk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_pk); } inline int qk_wrt_p1() const { return m_side_strategy.apply(m_pi, m_pj, m_qk); } inline int pk_wrt_q2() const { return m_side_strategy.apply(m_qj, m_qk, m_pk); } private : Pi const& m_pi; Pj const& m_pj; Pk const& m_pk; Qi const& m_qi; Qj const& m_qj; Qk const& m_qk; SideStrategy m_side_strategy; }; public: turns_analyser() : m_previous_turn_ptr(NULL) , m_previous_operation(overlay::operation_none) , m_boundary_counter(0) , m_interior_detected(false) , m_first_interior_other_id_ptr(NULL) , m_first_from_unknown(false) , m_first_from_unknown_boundary_detected(false) {} template <typename Result, typename TurnIt, typename Geometry, typename OtherGeometry, typename BoundaryChecker, typename SideStrategy> void apply(Result & res, TurnIt it, Geometry const& geometry, OtherGeometry const& other_geometry, BoundaryChecker const& boundary_checker, SideStrategy const& side_strategy) { overlay::operation_type op = it->operations[op_id].operation; if ( op != overlay::operation_union && op != overlay::operation_intersection && op != overlay::operation_blocked && op != overlay::operation_continue ) // operation_boundary / operation_boundary_intersection { return; } segment_identifier const& seg_id = it->operations[op_id].seg_id; segment_identifier const& other_id = it->operations[other_op_id].seg_id; const bool first_in_range = m_seg_watcher.update(seg_id); // TODO: should apply() for the post-last ip be called if first_in_range ? // this would unify how last points in ranges are handled // possibly replacing parts of the code below // e.g. for is_multi and m_interior_detected // handle possible exit bool fake_enter_detected = false; if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) { // real exit point - may be multiple // we know that we entered and now we exit if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it, side_strategy.get_equals_point_point_strategy()) ) { m_exit_watcher.reset_detected_exit(); update<interior, exterior, '1', TransposeResult>(res); // next single geometry if ( first_in_range && m_previous_turn_ptr ) { // NOTE: similar code is in the post-last-ip-apply() segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point if ( prev_back_b ) { update<boundary, exterior, '0', TransposeResult>(res); } } } // fake exit point, reset state else if ( op == overlay::operation_intersection || op == overlay::operation_continue ) // operation_boundary { m_exit_watcher.reset_detected_exit(); fake_enter_detected = true; } } else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked ) { // ignore multiple BLOCKs for this same single geometry1 if ( op == overlay::operation_blocked && seg_id.multi_index == m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) { return; } if ( ( op == overlay::operation_intersection || op == overlay::operation_continue ) && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it, side_strategy.get_equals_point_point_strategy()) ) { fake_enter_detected = true; } m_exit_watcher.reset_detected_exit(); } if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value ) && m_first_from_unknown ) { // For MultiPolygon many x/u operations may be generated as a first IP // if for all turns x/u was generated and any of the Polygons doesn't contain the LineString // then we know that the LineString is outside // Similar with the u/u turns, if it was the first one it doesn't mean that the // Linestring came from the exterior if ( ( m_previous_operation == overlay::operation_blocked && ( op != overlay::operation_blocked // operation different than block || seg_id.multi_index != m_previous_turn_ptr->operations[op_id].seg_id.multi_index ) ) // or the next single-geometry || ( m_previous_operation == overlay::operation_union && ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, side_strategy.get_equals_point_point_strategy()) ) ) { update<interior, exterior, '1', TransposeResult>(res); if ( m_first_from_unknown_boundary_detected ) { update<boundary, exterior, '0', TransposeResult>(res); } m_first_from_unknown = false; m_first_from_unknown_boundary_detected = false; } } // NOTE: THE WHOLE m_interior_detected HANDLING IS HERE BECAUSE WE CAN'T EFFICIENTLY SORT TURNS (CORRECTLY) // BECAUSE THE SAME IP MAY BE REPRESENTED BY TWO SEGMENTS WITH DIFFERENT DISTANCES // IT WOULD REQUIRE THE CALCULATION OF MAX DISTANCE // TODO: WE COULD GET RID OF THE TEST IF THE DISTANCES WERE NORMALIZED // UPDATE: THEY SHOULD BE NORMALIZED NOW // TODO: THIS IS POTENTIALLY ERROREOUS! // THIS ALGORITHM DEPENDS ON SOME SPECIFIC SEQUENCE OF OPERATIONS // IT WOULD GIVE WRONG RESULTS E.G. // IN THE CASE OF SELF-TOUCHING POINT WHEN 'i' WOULD BE BEFORE 'u' // handle the interior overlap if ( m_interior_detected ) { BOOST_GEOMETRY_ASSERT_MSG(m_previous_turn_ptr, "non-NULL ptr expected"); // real interior overlap if ( ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, side_strategy.get_equals_point_point_strategy()) ) { update<interior, interior, '1', TransposeResult>(res); m_interior_detected = false; // new range detected - reset previous state and check the boundary if ( first_in_range ) { segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point if ( prev_back_b ) { update<boundary, interior, '0', TransposeResult>(res); } // The exit_watcher is reset below // m_exit_watcher.reset(); } } // fake interior overlap else if ( op == overlay::operation_continue ) { m_interior_detected = false; } else if ( op == overlay::operation_union ) { // TODO: this probably is not a good way of handling the interiors/enters // the solution similar to exit_watcher would be more robust // all enters should be kept and handled. // maybe integrate it with the exit_watcher -> enter_exit_watcher if ( m_first_interior_other_id_ptr && m_first_interior_other_id_ptr->multi_index == other_id.multi_index ) { m_interior_detected = false; } } } // NOTE: If post-last-ip apply() was called this wouldn't be needed if ( first_in_range ) { m_exit_watcher.reset(); m_boundary_counter = 0; m_first_from_unknown = false; m_first_from_unknown_boundary_detected = false; } // i/u, c/u if ( op == overlay::operation_intersection || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection { bool const first_point = first_in_range || m_first_from_unknown; bool no_enters_detected = m_exit_watcher.is_outside(); m_exit_watcher.enter(*it); if ( op == overlay::operation_intersection ) { if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear ) --m_boundary_counter; if ( m_boundary_counter == 0 ) { // interiors overlaps //update<interior, interior, '1', TransposeResult>(res); // TODO: think about the implementation of the more robust version // this way only the first enter will be handled if ( !m_interior_detected ) { // don't update now // we might enter a boundary of some other ring on the same IP m_interior_detected = true; m_first_interior_other_id_ptr = boost::addressof(other_id); } } } else // operation_boundary { // don't add to the count for all met boundaries // only if this is the "new" boundary if ( first_point || !it->operations[op_id].is_collinear ) ++m_boundary_counter; update<interior, boundary, '1', TransposeResult>(res); } bool const this_b = is_ip_on_boundary<boundary_front>(it->point, it->operations[op_id], boundary_checker, seg_id); // going inside on boundary point if ( this_b ) { update<boundary, boundary, '0', TransposeResult>(res); } // going inside on non-boundary point else { update<interior, boundary, '0', TransposeResult>(res); // if we didn't enter in the past, we were outside if ( no_enters_detected && ! fake_enter_detected && it->operations[op_id].position != overlay::position_front ) { // TODO: calculate_from_inside() is only needed if the current Linestring is not closed bool const from_inside = first_point && calculate_from_inside(geometry, other_geometry, *it, side_strategy); if ( from_inside ) update<interior, interior, '1', TransposeResult>(res); else update<interior, exterior, '1', TransposeResult>(res); // if it's the first IP then the first point is outside if ( first_point ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point if ( front_b ) { if ( from_inside ) update<boundary, interior, '0', TransposeResult>(res); else update<boundary, exterior, '0', TransposeResult>(res); } } } } if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value ) ) { m_first_from_unknown = false; m_first_from_unknown_boundary_detected = false; } } // u/u, x/u else if ( op == overlay::operation_union || op == overlay::operation_blocked ) { bool const op_blocked = op == overlay::operation_blocked; bool const no_enters_detected = m_exit_watcher.is_outside() // TODO: is this condition ok? // TODO: move it into the exit_watcher? && m_exit_watcher.get_exit_operation() == overlay::operation_none; if ( op == overlay::operation_union ) { if ( m_boundary_counter > 0 && it->operations[op_id].is_collinear ) --m_boundary_counter; } else // overlay::operation_blocked { m_boundary_counter = 0; } // we're inside, possibly going out right now if ( ! no_enters_detected ) { if ( op_blocked && it->operations[op_id].position == overlay::position_back ) // ignore spikes! { // check if this is indeed the boundary point // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) ) { update<boundary, boundary, '0', TransposeResult>(res); } } // union, inside, but no exit -> collinear on self-intersection point // not needed since we're already inside the boundary /*else if ( !exit_detected ) { update<interior, boundary, '0', TransposeResult>(res); }*/ } // we're outside or inside and this is the first turn else { bool const this_b = is_ip_on_boundary<boundary_any>(it->point, it->operations[op_id], boundary_checker, seg_id); // if current IP is on boundary of the geometry if ( this_b ) { update<boundary, boundary, '0', TransposeResult>(res); } // if current IP is not on boundary of the geometry else { update<interior, boundary, '0', TransposeResult>(res); } // TODO: very similar code is used in the handling of intersection if ( it->operations[op_id].position != overlay::position_front ) { // TODO: calculate_from_inside() is only needed if the current Linestring is not closed // NOTE: this is not enough for MultiPolygon and operation_blocked // For LS/MultiPolygon multiple x/u turns may be generated // the first checked Polygon may be the one which LS is outside for. bool const first_point = first_in_range || m_first_from_unknown; bool const first_from_inside = first_point && calculate_from_inside(geometry, other_geometry, *it, side_strategy); if ( first_from_inside ) { update<interior, interior, '1', TransposeResult>(res); // notify the exit_watcher that we started inside m_exit_watcher.enter(*it); // and reset unknown flags since we know that we started inside m_first_from_unknown = false; m_first_from_unknown_boundary_detected = false; } else { if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value ) /*&& ( op == overlay::operation_blocked || op == overlay::operation_union )*/ ) // if we're here it's u or x { m_first_from_unknown = true; } else { update<interior, exterior, '1', TransposeResult>(res); } } // first IP on the last segment point - this means that the first point is outside or inside if ( first_point && ( !this_b || op_blocked ) ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point if ( front_b ) { if ( first_from_inside ) { update<boundary, interior, '0', TransposeResult>(res); } else { if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value ) /*&& ( op == overlay::operation_blocked || op == overlay::operation_union )*/ ) // if we're here it's u or x { BOOST_GEOMETRY_ASSERT(m_first_from_unknown); m_first_from_unknown_boundary_detected = true; } else { update<boundary, exterior, '0', TransposeResult>(res); } } } } } } // if we're going along a boundary, we exit only if the linestring was collinear if ( m_boundary_counter == 0 || it->operations[op_id].is_collinear ) { // notify the exit watcher about the possible exit m_exit_watcher.exit(*it); } } // store ref to previously analysed (valid) turn m_previous_turn_ptr = boost::addressof(*it); // and previously analysed (valid) operation m_previous_operation = op; } // it == last template <typename Result, typename TurnIt, typename Geometry, typename OtherGeometry, typename BoundaryChecker> void apply(Result & res, TurnIt first, TurnIt last, Geometry const& geometry, OtherGeometry const& /*other_geometry*/, BoundaryChecker const& boundary_checker) { boost::ignore_unused(first, last); //BOOST_GEOMETRY_ASSERT( first != last ); // For MultiPolygon many x/u operations may be generated as a first IP // if for all turns x/u was generated and any of the Polygons doesn't contain the LineString // then we know that the LineString is outside if ( BOOST_GEOMETRY_CONDITION( util::is_multi<OtherGeometry>::value ) && m_first_from_unknown ) { update<interior, exterior, '1', TransposeResult>(res); if ( m_first_from_unknown_boundary_detected ) { update<boundary, exterior, '0', TransposeResult>(res); } // done below //m_first_from_unknown = false; //m_first_from_unknown_boundary_detected = false; } // here, the possible exit is the real one // we know that we entered and now we exit if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT ||*/ m_previous_operation == overlay::operation_union && !m_interior_detected ) { // for sure update<interior, exterior, '1', TransposeResult>(res); BOOST_GEOMETRY_ASSERT(first != last); BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr); segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point if ( prev_back_b ) { update<boundary, exterior, '0', TransposeResult>(res); } } // we might enter some Areal and didn't go out, else if ( m_previous_operation == overlay::operation_intersection || m_interior_detected ) { // just in case update<interior, interior, '1', TransposeResult>(res); m_interior_detected = false; BOOST_GEOMETRY_ASSERT(first != last); BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr); segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point if ( prev_back_b ) { update<boundary, interior, '0', TransposeResult>(res); } } // This condition may be false if the Linestring is lying on the Polygon's collinear spike // if Polygon's spikes are not handled in get_turns() or relate() (they currently aren't) //BOOST_GEOMETRY_ASSERT_MSG(m_previous_operation != overlay::operation_continue, // "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)"); // Currently one c/c turn is generated for the exit // when a Linestring is going out on a collinear spike // When a Linestring is going in on a collinear spike // the turn is not generated for the entry // So assume it's the former if ( m_previous_operation == overlay::operation_continue ) { update<interior, exterior, '1', TransposeResult>(res); segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point if ( prev_back_b ) { update<boundary, exterior, '0', TransposeResult>(res); } } // Reset exit watcher before the analysis of the next Linestring m_exit_watcher.reset(); m_boundary_counter = 0; m_first_from_unknown = false; m_first_from_unknown_boundary_detected = false; } // check if the passed turn's segment of Linear geometry arrived // from the inside or the outside of the Areal geometry template <typename Turn, typename SideStrategy> static inline bool calculate_from_inside(Geometry1 const& geometry1, Geometry2 const& geometry2, Turn const& turn, SideStrategy const& side_strategy) { typedef typename cs_tag<typename Turn::point_type>::type cs_tag; if ( turn.operations[op_id].position == overlay::position_front ) return false; typename sub_range_return_type<Geometry1 const>::type range1 = sub_range(geometry1, turn.operations[op_id].seg_id); typedef detail::normalized_view<Geometry2 const> const range2_type; typedef typename boost::range_iterator<range2_type>::type range2_iterator; range2_type range2(sub_range(geometry2, turn.operations[other_op_id].seg_id)); BOOST_GEOMETRY_ASSERT(boost::size(range1)); std::size_t const s2 = boost::size(range2); BOOST_GEOMETRY_ASSERT(s2 > 2); std::size_t const seg_count2 = s2 - 1; std::size_t const p_seg_ij = static_cast<std::size_t>(turn.operations[op_id].seg_id.segment_index); std::size_t const q_seg_ij = static_cast<std::size_t>(turn.operations[other_op_id].seg_id.segment_index); BOOST_GEOMETRY_ASSERT(p_seg_ij + 1 < boost::size(range1)); BOOST_GEOMETRY_ASSERT(q_seg_ij + 1 < s2); point1_type const& pi = range::at(range1, p_seg_ij); point2_type const& qi = range::at(range2, q_seg_ij); point2_type const& qj = range::at(range2, q_seg_ij + 1); point1_type qi_conv; geometry::convert(qi, qi_conv); bool const is_ip_qj = equals::equals_point_point(turn.point, qj, side_strategy.get_equals_point_point_strategy()); // TODO: test this! // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, pi)); // BOOST_GEOMETRY_ASSERT(!equals::equals_point_point(turn.point, qi)); point1_type new_pj; geometry::convert(turn.point, new_pj); if ( is_ip_qj ) { std::size_t const q_seg_jk = (q_seg_ij + 1) % seg_count2; // TODO: the following function should return immediately, however the worst case complexity is O(N) // It would be good to replace it with some O(1) mechanism range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2), range::pos(range2, q_seg_jk), boost::end(range2), side_strategy.get_equals_point_point_strategy()); // Will this sequence of points be always correct? la_side_calculator<cs_tag, point1_type, point2_type, SideStrategy> side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it, side_strategy); return calculate_from_inside_sides(side_calc); } else { point2_type new_qj; geometry::convert(turn.point, new_qj); la_side_calculator<cs_tag, point1_type, point2_type, SideStrategy> side_calc(qi_conv, new_pj, pi, qi, new_qj, qj, side_strategy); return calculate_from_inside_sides(side_calc); } } template <typename It, typename EqPPStrategy> static inline It find_next_non_duplicated(It first, It current, It last, EqPPStrategy const& strategy) { BOOST_GEOMETRY_ASSERT( current != last ); It it = current; for ( ++it ; it != last ; ++it ) { if ( !equals::equals_point_point(*current, *it, strategy) ) return it; } // if not found start from the beginning for ( it = first ; it != current ; ++it ) { if ( !equals::equals_point_point(*current, *it, strategy) ) return it; } return current; } // calculate inside or outside based on side_calc // this is simplified version of a check from equal<> template <typename SideCalc> static inline bool calculate_from_inside_sides(SideCalc const& side_calc) { int const side_pk_p = side_calc.pk_wrt_p1(); int const side_qk_p = side_calc.qk_wrt_p1(); // If they turn to same side (not opposite sides) if (! overlay::base_turn_handler::opposite(side_pk_p, side_qk_p)) { int const side_pk_q2 = side_calc.pk_wrt_q2(); return side_pk_q2 == -1; } else { return side_pk_p == -1; } } private: exit_watcher<TurnInfo, op_id> m_exit_watcher; segment_watcher<same_single> m_seg_watcher; TurnInfo * m_previous_turn_ptr; overlay::operation_type m_previous_operation; unsigned m_boundary_counter; bool m_interior_detected; const segment_identifier * m_first_interior_other_id_ptr; bool m_first_from_unknown; bool m_first_from_unknown_boundary_detected; }; // call analyser.apply() for each turn in range // IMPORTANT! The analyser is also called for the end iterator - last template <typename Result, typename TurnIt, typename Analyser, typename Geometry, typename OtherGeometry, typename BoundaryChecker, typename SideStrategy> static inline void analyse_each_turn(Result & res, Analyser & analyser, TurnIt first, TurnIt last, Geometry const& geometry, OtherGeometry const& other_geometry, BoundaryChecker const& boundary_checker, SideStrategy const& side_strategy) { if ( first == last ) return; for ( TurnIt it = first ; it != last ; ++it ) { analyser.apply(res, it, geometry, other_geometry, boundary_checker, side_strategy); if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) ) return; } analyser.apply(res, first, last, geometry, other_geometry, boundary_checker); } // less comparator comparing multi_index then ring_index // may be used to sort turns by ring struct less_ring { template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { return left.operations[1].seg_id.multi_index < right.operations[1].seg_id.multi_index || ( left.operations[1].seg_id.multi_index == right.operations[1].seg_id.multi_index && left.operations[1].seg_id.ring_index < right.operations[1].seg_id.ring_index ); } }; // policy/functor checking if a turn's operation is operation_continue struct has_boundary_intersection { has_boundary_intersection() : result(false) {} template <typename Turn> inline void operator()(Turn const& turn) { if ( turn.operations[1].operation == overlay::operation_continue ) result = true; } bool result; }; // iterate through the range and search for the different multi_index or ring_index // also call fun for each turn in the current range template <typename It, typename Fun> static inline It find_next_ring(It first, It last, Fun & fun) { if ( first == last ) return last; signed_size_type const multi_index = first->operations[1].seg_id.multi_index; signed_size_type const ring_index = first->operations[1].seg_id.ring_index; fun(*first); ++first; for ( ; first != last ; ++first ) { if ( multi_index != first->operations[1].seg_id.multi_index || ring_index != first->operations[1].seg_id.ring_index ) { return first; } fun(*first); } return last; } // analyser which called for turns sorted by seg/distance/operation // checks if the boundary of Areal geometry really got out // into the exterior of Linear geometry template <typename TurnInfo> class areal_boundary_analyser { public: areal_boundary_analyser() : is_union_detected(false) , m_previous_turn_ptr(NULL) {} template <typename TurnIt, typename EqPPStrategy> bool apply(TurnIt /*first*/, TurnIt it, TurnIt last, EqPPStrategy const& strategy) { overlay::operation_type op = it->operations[1].operation; if ( it != last ) { if ( op != overlay::operation_union && op != overlay::operation_continue ) { return true; } if ( is_union_detected ) { BOOST_GEOMETRY_ASSERT(m_previous_turn_ptr != NULL); if ( !detail::equals::equals_point_point(it->point, m_previous_turn_ptr->point, strategy) ) { // break return false; } else if ( op == overlay::operation_continue ) // operation_boundary { is_union_detected = false; } } if ( op == overlay::operation_union ) { is_union_detected = true; m_previous_turn_ptr = boost::addressof(*it); } return true; } else { return false; } } bool is_union_detected; private: const TurnInfo * m_previous_turn_ptr; }; }; template <typename Geometry1, typename Geometry2> struct areal_linear { typedef linear_areal<Geometry2, Geometry1, true> linear_areal_type; static const bool interruption_enabled = linear_areal_type::interruption_enabled; template <typename Result, typename IntersectionStrategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, IntersectionStrategy const& intersection_strategy) { linear_areal_type::apply(geometry2, geometry1, result, intersection_strategy); } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP detail/relate/relate_impl.hpp 0000644 00000005470 15125631656 0012310 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_IMPL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_IMPL_HPP #include <type_traits> #include <boost/geometry/algorithms/detail/relate/interface.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/tag.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { struct implemented_tag {}; template < typename Geometry1, typename Geometry2 > struct relate_impl_base : std::conditional_t < std::is_base_of < nyi::not_implemented_tag, dispatch::relate<Geometry1, Geometry2> >::value, not_implemented < typename geometry::tag<Geometry1>::type, typename geometry::tag<Geometry2>::type >, implemented_tag > {}; template < typename Geometry1, typename Geometry2, typename StaticMask > struct relate_impl_dispatch : relate_impl_base<Geometry1, Geometry2> { template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { typename detail::relate::result_handler_type < Geometry1, Geometry2, StaticMask >::type handler; dispatch::relate<Geometry1, Geometry2>::apply(g1, g2, handler, strategy); return handler.result(); } }; template <typename Geometry1, typename Geometry2> struct relate_impl_dispatch<Geometry1, Geometry2, detail::relate::false_mask> : relate_impl_base<Geometry1, Geometry2> { template <typename Strategy> static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const& ) { return false; } }; template < template <typename, typename> class StaticMaskTrait, typename Geometry1, typename Geometry2 > struct relate_impl : relate_impl_dispatch < Geometry1, Geometry2, typename StaticMaskTrait<Geometry1, Geometry2>::type > {}; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RELATE_IMPL_HPP detail/relate/multi_point_geometry.hpp 0000644 00000056225 15125631656 0014275 0 ustar 00 // Boost.Geometry // Copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/relate/result.hpp> #include <boost/geometry/algorithms/detail/relate/topology_check.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/index/rtree.hpp> // TEMP #include <boost/geometry/strategies/envelope/cartesian.hpp> #include <boost/geometry/strategies/envelope/geographic.hpp> #include <boost/geometry/strategies/envelope/spherical.hpp> #include <boost/geometry/util/type_traits.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template < typename Geometry, typename EqPPStrategy, typename Tag = typename tag<Geometry>::type > struct multi_point_geometry_eb { template <typename MultiPoint> static inline bool apply(MultiPoint const& , detail::relate::topology_check<Geometry, EqPPStrategy> const& ) { return true; } }; template <typename Geometry, typename EqPPStrategy> struct multi_point_geometry_eb<Geometry, EqPPStrategy, linestring_tag> { template <typename Points> struct boundary_visitor { boundary_visitor(Points const& points) : m_points(points) , m_boundary_found(false) {} template <typename Point> struct find_pred { find_pred(Point const& point) : m_point(point) {} template <typename Pt> bool operator()(Pt const& pt) const { return detail::equals::equals_point_point(pt, m_point, EqPPStrategy()); } Point const& m_point; }; template <typename Point> bool apply(Point const& boundary_point) { if (std::find_if(m_points.begin(), m_points.end(), find_pred<Point>(boundary_point)) == m_points.end()) { m_boundary_found = true; return false; } return true; } bool result() const { return m_boundary_found; } private: Points const& m_points; bool m_boundary_found; }; template <typename MultiPoint> static inline bool apply(MultiPoint const& multi_point, detail::relate::topology_check<Geometry, EqPPStrategy> const& tc) { boundary_visitor<MultiPoint> visitor(multi_point); tc.for_each_boundary_point(visitor); return visitor.result(); } }; template <typename Geometry, typename EqPPStrategy> struct multi_point_geometry_eb<Geometry, EqPPStrategy, multi_linestring_tag> { // TODO: CS-specific less compare strategy derived from EqPPStrategy typedef geometry::less<void, -1, typename EqPPStrategy::cs_tag> less_type; template <typename Points> struct boundary_visitor { boundary_visitor(Points const& points) : m_points(points) , m_boundary_found(false) {} template <typename Point> bool apply(Point const& boundary_point) { if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, less_type())) { m_boundary_found = true; return false; } return true; } bool result() const { return m_boundary_found; } private: Points const& m_points; bool m_boundary_found; }; template <typename MultiPoint> static inline bool apply(MultiPoint const& multi_point, detail::relate::topology_check<Geometry, EqPPStrategy> const& tc) { typedef typename boost::range_value<MultiPoint>::type point_type; typedef std::vector<point_type> points_type; points_type points(boost::begin(multi_point), boost::end(multi_point)); std::sort(points.begin(), points.end(), less_type()); boundary_visitor<points_type> visitor(points); tc.for_each_boundary_point(visitor); return visitor.result(); } }; // SingleGeometry - Linear or Areal template <typename MultiPoint, typename SingleGeometry, bool Transpose = false> struct multi_point_single_geometry { static const bool interruption_enabled = true; template <typename Result, typename Strategy> static inline void apply(MultiPoint const& multi_point, SingleGeometry const& single_geometry, Result & result, Strategy const& strategy) { typedef typename point_type<SingleGeometry>::type point2_type; typedef model::box<point2_type> box2_type; typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type; typedef typename Strategy::disjoint_point_box_strategy_type d_pb_strategy_type; box2_type box2; geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy()); geometry::detail::expand_by_epsilon(box2); typedef typename boost::range_const_iterator<MultiPoint>::type iterator; for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { if (! (relate::may_update<interior, interior, '0', Transpose>(result) || relate::may_update<interior, boundary, '0', Transpose>(result) || relate::may_update<interior, exterior, '0', Transpose>(result) ) ) { break; } // The default strategy is enough for Point/Box if (detail::disjoint::disjoint_point_box(*it, box2, d_pb_strategy_type())) { relate::set<interior, exterior, '0', Transpose>(result); } else { int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy); if (in_val > 0) // within { relate::set<interior, interior, '0', Transpose>(result); } else if (in_val == 0) { relate::set<interior, boundary, '0', Transpose>(result); } else // in_val < 0 - not within { relate::set<interior, exterior, '0', Transpose>(result); } } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) { return; } } typedef detail::relate::topology_check < SingleGeometry, eq_pp_strategy_type > tc_t; if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) ) { tc_t tc(single_geometry); if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) && tc.has_interior() ) { // TODO: this is not true if a linestring is degenerated to a point // then the interior has topological dimension = 0, not 1 relate::set<exterior, interior, tc_t::interior, Transpose>(result); } if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) && tc.has_boundary() ) { if (multi_point_geometry_eb < SingleGeometry, eq_pp_strategy_type >::apply(multi_point, tc)) { relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); } } } relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result); } }; // MultiGeometry - Linear or Areal // part of the algorithm calculating II and IB when no IE has to be calculated // using partition() template <typename MultiPoint, typename MultiGeometry, bool Transpose> class multi_point_multi_geometry_ii_ib { template <typename ExpandPointStrategy> struct expand_box_point { template <typename Box, typename Point> static inline void apply(Box& total, Point const& point) { geometry::expand(total, point, ExpandPointStrategy()); } }; template <typename ExpandBoxStrategy> struct expand_box_box_pair { template <typename Box, typename BoxPair> static inline void apply(Box& total, BoxPair const& box_pair) { geometry::expand(total, box_pair.first, ExpandBoxStrategy()); } }; template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { // The default strategy is enough for Point/Box return ! detail::disjoint::disjoint_point_box(point, box, DisjointPointBoxStrategy()); } }; template <typename DisjointBoxBoxStrategy> struct overlaps_box_box_pair { template <typename Box, typename BoxPair> static inline bool apply(Box const& box, BoxPair const& box_pair) { // The default strategy is enough for Box/Box return ! detail::disjoint::disjoint_box_box(box_pair.first, box, DisjointBoxBoxStrategy()); } }; template <typename Result, typename PtSegStrategy> class item_visitor_type { typedef typename PtSegStrategy::equals_point_point_strategy_type pp_strategy_type; typedef typename PtSegStrategy::disjoint_point_box_strategy_type d_pp_strategy_type; typedef detail::relate::topology_check<MultiGeometry, pp_strategy_type> topology_check_type; public: item_visitor_type(MultiGeometry const& multi_geometry, topology_check_type const& tc, Result & result, PtSegStrategy const& strategy) : m_multi_geometry(multi_geometry) , m_tc(tc) , m_result(result) , m_strategy(strategy) {} template <typename Point, typename BoxPair> inline bool apply(Point const& point, BoxPair const& box_pair) { // The default strategy is enough for Point/Box if (! detail::disjoint::disjoint_point_box(point, box_pair.first, d_pp_strategy_type())) { typename boost::range_value<MultiGeometry>::type const& single = range::at(m_multi_geometry, box_pair.second); int in_val = detail::within::point_in_geometry(point, single, m_strategy); if (in_val > 0) // within { relate::set<interior, interior, '0', Transpose>(m_result); } else if (in_val == 0) { if (m_tc.check_boundary_point(point)) relate::set<interior, boundary, '0', Transpose>(m_result); else relate::set<interior, interior, '0', Transpose>(m_result); } } if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) ) { return false; } if (! (relate::may_update<interior, interior, '0', Transpose>(m_result) || relate::may_update<interior, boundary, '0', Transpose>(m_result) ) ) { return false; } return true; } private: MultiGeometry const& m_multi_geometry; topology_check_type const& m_tc; Result & m_result; PtSegStrategy const& m_strategy; }; public: typedef typename point_type<MultiPoint>::type point1_type; typedef typename point_type<MultiGeometry>::type point2_type; typedef model::box<point1_type> box1_type; typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; template <typename Result, typename Strategy> static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, std::vector<box_pair_type> const& boxes, detail::relate::topology_check < MultiGeometry, typename Strategy::equals_point_point_strategy_type > const& tc, Result & result, Strategy const& strategy) { item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy); typedef expand_box_point < typename Strategy::expand_point_strategy_type > expand_box_point_type; typedef overlaps_box_point < typename Strategy::disjoint_point_box_strategy_type > overlaps_box_point_type; typedef expand_box_box_pair < // TEMP - envelope umbrella strategy also contains // expand strategies decltype(strategies::envelope::services::strategy_converter < typename Strategy::envelope_strategy_type >::get(strategy.get_envelope_strategy()) .expand(std::declval<box1_type>(), std::declval<box2_type>())) > expand_box_box_pair_type; typedef overlaps_box_box_pair < typename Strategy::disjoint_box_box_strategy_type > overlaps_box_box_pair_type; geometry::partition < box1_type >::apply(multi_point, boxes, visitor, expand_box_point_type(), overlaps_box_point_type(), expand_box_box_pair_type(), overlaps_box_box_pair_type()); } }; // MultiGeometry - Linear or Areal // part of the algorithm calculating II, IB and IE // using rtree template <typename MultiPoint, typename MultiGeometry, bool Transpose> struct multi_point_multi_geometry_ii_ib_ie { typedef typename point_type<MultiPoint>::type point1_type; typedef typename point_type<MultiGeometry>::type point2_type; typedef model::box<point1_type> box1_type; typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; typedef std::vector<box_pair_type> boxes_type; typedef typename boxes_type::const_iterator boxes_iterator; template <typename Result, typename Strategy> static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, std::vector<box_pair_type> const& boxes, detail::relate::topology_check < MultiGeometry, typename Strategy::equals_point_point_strategy_type > const& tc, Result & result, Strategy const& strategy) { typedef strategy::index::services::from_strategy < Strategy > index_strategy_from; typedef index::parameters < index::rstar<4>, typename index_strategy_from::type > index_parameters_type; index::rtree<box_pair_type, index_parameters_type> rtree(boxes.begin(), boxes.end(), index_parameters_type(index::rstar<4>(), index_strategy_from::get(strategy))); typedef typename boost::range_const_iterator<MultiPoint>::type iterator; for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { if (! (relate::may_update<interior, interior, '0', Transpose>(result) || relate::may_update<interior, boundary, '0', Transpose>(result) || relate::may_update<interior, exterior, '0', Transpose>(result) ) ) { return; } typename boost::range_value<MultiPoint>::type const& point = *it; boxes_type boxes_found; rtree.query(index::intersects(point), std::back_inserter(boxes_found)); bool found_ii_or_ib = false; for (boxes_iterator bi = boxes_found.begin() ; bi != boxes_found.end() ; ++bi) { typename boost::range_value<MultiGeometry>::type const& single = range::at(multi_geometry, bi->second); int in_val = detail::within::point_in_geometry(point, single, strategy); if (in_val > 0) // within { relate::set<interior, interior, '0', Transpose>(result); found_ii_or_ib = true; } else if (in_val == 0) // on boundary of single { if (tc.check_boundary_point(point)) relate::set<interior, boundary, '0', Transpose>(result); else relate::set<interior, interior, '0', Transpose>(result); found_ii_or_ib = true; } } // neither interior nor boundary found -> exterior if (found_ii_or_ib == false) { relate::set<interior, exterior, '0', Transpose>(result); } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) { return; } } } }; // MultiGeometry - Linear or Areal template <typename MultiPoint, typename MultiGeometry, bool Transpose = false> struct multi_point_multi_geometry { static const bool interruption_enabled = true; template <typename Result, typename Strategy> static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Result & result, Strategy const& strategy) { typedef typename point_type<MultiGeometry>::type point2_type; typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type; typename Strategy::envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); std::size_t count2 = boost::size(multi_geometry); std::vector<box_pair_type> boxes(count2); for (std::size_t i = 0 ; i < count2 ; ++i) { geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy); geometry::detail::expand_by_epsilon(boxes[i].first); boxes[i].second = i; } typedef detail::relate::topology_check<MultiGeometry, eq_pp_strategy_type> tc_t; tc_t tc(multi_geometry); if ( relate::may_update<interior, interior, '0', Transpose>(result) || relate::may_update<interior, boundary, '0', Transpose>(result) || relate::may_update<interior, exterior, '0', Transpose>(result) ) { // If there is no need to calculate IE, use partition if (! relate::may_update<interior, exterior, '0', Transpose>(result) ) { multi_point_multi_geometry_ii_ib<MultiPoint, MultiGeometry, Transpose> ::apply(multi_point, multi_geometry, boxes, tc, result, strategy); } else // otherwise use rtree { multi_point_multi_geometry_ii_ib_ie<MultiPoint, MultiGeometry, Transpose> ::apply(multi_point, multi_geometry, boxes, tc, result, strategy); } } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) { return; } if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) ) { if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result) && tc.has_interior() ) { // TODO: this is not true if a linestring is degenerated to a point // then the interior has topological dimension = 0, not 1 relate::set<exterior, interior, tc_t::interior, Transpose>(result); } if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) && tc.has_boundary() ) { if (multi_point_geometry_eb < MultiGeometry, eq_pp_strategy_type >::apply(multi_point, tc)) { relate::set<exterior, boundary, tc_t::boundary, Transpose>(result); } } } relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result); } }; template < typename MultiPoint, typename Geometry, bool Transpose = false, bool isMulti = util::is_multi<Geometry>::value > struct multi_point_geometry : multi_point_single_geometry<MultiPoint, Geometry, Transpose> {}; template <typename MultiPoint, typename Geometry, bool Transpose> struct multi_point_geometry<MultiPoint, Geometry, Transpose, true> : multi_point_multi_geometry<MultiPoint, Geometry, Transpose> {}; // transposed result of multi_point_geometry template <typename Geometry, typename MultiPoint> struct geometry_multi_point { static const bool interruption_enabled = true; template <typename Result, typename Strategy> static inline void apply(Geometry const& geometry, MultiPoint const& multi_point, Result & result, Strategy const& strategy) { multi_point_geometry<MultiPoint, Geometry, true>::apply(multi_point, geometry, result, strategy); } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP detail/relate/implementation.hpp 0000644 00000010650 15125631656 0013034 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2015, 2017. // Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/relate/interface.hpp> #include <boost/geometry/algorithms/detail/relate/point_point.hpp> #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/linear_linear.hpp> #include <boost/geometry/algorithms/detail/relate/linear_areal.hpp> #include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/areal_areal.hpp> #include <boost/geometry/strategies/intersection.hpp> #include <boost/geometry/strategies/within.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point1, typename Point2> struct relate<Point1, Point2, point_tag, point_tag, 0, 0, false> : detail::relate::point_point<Point1, Point2> {}; template <typename Point, typename MultiPoint> struct relate<Point, MultiPoint, point_tag, multi_point_tag, 0, 0, false> : detail::relate::point_multipoint<Point, MultiPoint> {}; template <typename MultiPoint, typename Point> struct relate<MultiPoint, Point, multi_point_tag, point_tag, 0, 0, false> : detail::relate::multipoint_point<MultiPoint, Point> {}; template <typename MultiPoint1, typename MultiPoint2> struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, 0, 0, false> : detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2> {}; // TODO - for now commented out because before implementing it we must consider: // 1. how the Box degenerated to a Point should be treated // 2. what should be the definition of a Box degenerated to a Point // 3. what fields should the matrix/mask contain for dimension > 2 and dimension > 9 // //template <typename Point, typename Box, int TopDim2> //struct relate<Point, Box, point_tag, box_tag, 0, TopDim2, false> // : detail::relate::point_box<Point, Box> //{}; // //template <typename Box, typename Point, int TopDim1> //struct relate<Box, Point, box_tag, point_tag, TopDim1, 0, false> // : detail::relate::box_point<Box, Point> //{}; template <typename Point, typename Geometry, typename Tag2, int TopDim2> struct relate<Point, Geometry, point_tag, Tag2, 0, TopDim2, true> : detail::relate::point_geometry<Point, Geometry> {}; template <typename Geometry, typename Point, typename Tag1, int TopDim1> struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true> : detail::relate::geometry_point<Geometry, Point> {}; template <typename MultiPoint, typename Geometry, typename Tag2, int TopDim2> struct relate<MultiPoint, Geometry, multi_point_tag, Tag2, 0, TopDim2, false> : detail::relate::multi_point_geometry<MultiPoint, Geometry> {}; template <typename Geometry, typename MultiPoint, typename Tag1, int TopDim1> struct relate<Geometry, MultiPoint, Tag1, multi_point_tag, TopDim1, 0, false> : detail::relate::geometry_multi_point<Geometry, MultiPoint> {}; template <typename Linear1, typename Linear2, typename Tag1, typename Tag2> struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true> : detail::relate::linear_linear<Linear1, Linear2> {}; template <typename Linear, typename Areal, typename Tag1, typename Tag2> struct relate<Linear, Areal, Tag1, Tag2, 1, 2, true> : detail::relate::linear_areal<Linear, Areal> {}; template <typename Areal, typename Linear, typename Tag1, typename Tag2> struct relate<Areal, Linear, Tag1, Tag2, 2, 1, true> : detail::relate::areal_linear<Areal, Linear> {}; template <typename Areal1, typename Areal2, typename Tag1, typename Tag2> struct relate<Areal1, Areal2, Tag1, Tag2, 2, 2, true> : detail::relate::areal_areal<Areal1, Areal2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_HPP detail/relate/turns.hpp 0000644 00000026473 15125631656 0011174 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/strategies/cartesian/point_in_point.hpp> #include <boost/geometry/strategies/spherical/point_in_point.hpp> #include <boost/geometry/strategies/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { namespace turns { template <bool IncludeDegenerate = false> struct assign_policy : overlay::assign_null_policy { static bool const include_degenerate = IncludeDegenerate; }; // GET_TURNS template < typename Geometry1, typename Geometry2, typename GetTurnPolicy = detail::get_turns::get_turn_info_type < Geometry1, Geometry2, assign_policy<> > > struct get_turns { typedef typename geometry::point_type<Geometry1>::type point1_type; template <typename Strategy> struct robust_policy_type : geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag > {}; template < typename Strategy, typename RobustPolicy = typename robust_policy_type<Strategy>::type > struct turn_info_type { typedef typename segment_ratio_type<point1_type, RobustPolicy>::type ratio_type; typedef overlay::turn_info < point1_type, ratio_type, typename detail::get_turns::turn_operation_type < Geometry1, Geometry2, ratio_type >::type > type; }; template <typename Turns> static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2) { detail::get_turns::no_interrupt_policy interrupt_policy; typename strategy::intersection::services::default_strategy < typename cs_tag<Geometry1>::type >::type intersection_strategy; apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); } template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy> static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2, InterruptPolicy & interrupt_policy, IntersectionStrategy const& intersection_strategy) { typedef typename robust_policy_type<IntersectionStrategy>::type robust_policy_t; robust_policy_t robust_policy = geometry::get_rescale_policy<robust_policy_t>( geometry1, geometry2, intersection_strategy); apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy, robust_policy); } template <typename Turns, typename InterruptPolicy, typename IntersectionStrategy, typename RobustPolicy> static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2, InterruptPolicy & interrupt_policy, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) { static const bool reverse1 = detail::overlay::do_reverse < geometry::point_order<Geometry1>::value >::value; static const bool reverse2 = detail::overlay::do_reverse < geometry::point_order<Geometry2>::value >::value; dispatch::get_turns < typename geometry::tag<Geometry1>::type, typename geometry::tag<Geometry2>::type, Geometry1, Geometry2, reverse1, reverse2, GetTurnPolicy >::apply(0, geometry1, 1, geometry2, intersection_strategy, robust_policy, turns, interrupt_policy); } }; // TURNS SORTING AND SEARCHING template <int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0> struct op_to_int { template <typename Operation> inline int operator()(Operation const& op) const { switch(op.operation) { case detail::overlay::operation_none : return N; case detail::overlay::operation_union : return U; case detail::overlay::operation_intersection : return I; case detail::overlay::operation_blocked : return B; case detail::overlay::operation_continue : return C; case detail::overlay::operation_opposite : return O; } return -1; } }; template <std::size_t OpId, typename OpToInt> struct less_op_xxx_linear { template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { static OpToInt op_to_int; return op_to_int(left.operations[OpId]) < op_to_int(right.operations[OpId]); } }; template <std::size_t OpId> struct less_op_linear_linear : less_op_xxx_linear< OpId, op_to_int<0,2,3,1,4,0> > {}; template <std::size_t OpId> struct less_op_linear_areal_single { template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { static const std::size_t other_op_id = (OpId + 1) % 2; static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic; static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc; segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id; segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id; typedef typename Turn::turn_operation_type operation_type; operation_type const& left_operation = left.operations[OpId]; operation_type const& right_operation = right.operations[OpId]; if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index ) { return op_to_int_xuic(left_operation) < op_to_int_xuic(right_operation); } else { return op_to_int_xiuc(left_operation) < op_to_int_xiuc(right_operation); } } }; template <std::size_t OpId> struct less_op_areal_linear : less_op_xxx_linear< OpId, op_to_int<0,1,0,0,2,0> > {}; template <std::size_t OpId> struct less_op_areal_areal { template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { static const std::size_t other_op_id = (OpId + 1) % 2; static op_to_int<0, 1, 2, 3, 4, 0> op_to_int_uixc; static op_to_int<0, 2, 1, 3, 4, 0> op_to_int_iuxc; segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id; segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id; typedef typename Turn::turn_operation_type operation_type; operation_type const& left_operation = left.operations[OpId]; operation_type const& right_operation = right.operations[OpId]; if ( left_other_seg_id.multi_index == right_other_seg_id.multi_index ) { if ( left_other_seg_id.ring_index == right_other_seg_id.ring_index ) { return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation); } else { if ( left_other_seg_id.ring_index == -1 ) { if ( left_operation.operation == overlay::operation_union ) return false; else if ( left_operation.operation == overlay::operation_intersection ) return true; } else if ( right_other_seg_id.ring_index == -1 ) { if ( right_operation.operation == overlay::operation_union ) return true; else if ( right_operation.operation == overlay::operation_intersection ) return false; } return op_to_int_iuxc(left_operation) < op_to_int_iuxc(right_operation); } } else { return op_to_int_uixc(left_operation) < op_to_int_uixc(right_operation); } } }; template <std::size_t OpId> struct less_other_multi_index { static const std::size_t other_op_id = (OpId + 1) % 2; template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { return left.operations[other_op_id].seg_id.multi_index < right.operations[other_op_id].seg_id.multi_index; } }; // sort turns by G1 - source_index == 0 by: // seg_id -> distance and coordinates -> operation template <std::size_t OpId, typename LessOp, typename CSTag> struct less { BOOST_STATIC_ASSERT(OpId < 2); template <typename Turn> static inline bool use_fraction(Turn const& left, Turn const& right) { typedef typename geometry::strategy::within::services::default_strategy < typename Turn::point_type, typename Turn::point_type, point_tag, point_tag, pointlike_tag, pointlike_tag, typename tag_cast<CSTag, spherical_tag>::type, typename tag_cast<CSTag, spherical_tag>::type >::type eq_pp_strategy_type; static LessOp less_op; // NOTE: Assuming fraction is more permissive and faster than // comparison of points with strategy. return geometry::math::equals(left.operations[OpId].fraction, right.operations[OpId].fraction) && eq_pp_strategy_type::apply(left.point, right.point) ? less_op(left, right) : (left.operations[OpId].fraction < right.operations[OpId].fraction) ; } template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { segment_identifier const& sl = left.operations[OpId].seg_id; segment_identifier const& sr = right.operations[OpId].seg_id; return sl < sr || ( sl == sr && use_fraction(left, right) ); } }; }}} // namespace detail::relate::turns #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP detail/relate/result.hpp 0000644 00000101524 15125631656 0011326 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #include <algorithm> #include <cstddef> #include <cstring> #include <type_traits> #include <boost/throw_exception.hpp> #include <boost/tuple/tuple.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/exception.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/sequence.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { enum field { interior = 0, boundary = 1, exterior = 2 }; // TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES // THE VALUE ALREADY STORED MUSN'T BE CHECKED // update() calls chould be replaced with set() in those cases // but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that // so some additional function could be added, e.g. set_dim() // --------------- MATRIX ---------------- // matrix template <std::size_t Height, std::size_t Width = Height> class matrix { public: typedef char value_type; typedef std::size_t size_type; typedef const char * const_iterator; typedef const_iterator iterator; static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; inline matrix() { ::memset(m_array, 'F', static_size); } template <field F1, field F2> inline char get() const { BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); return m_array[index]; } template <field F1, field F2, char V> inline void set() { BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); m_array[index] = V; } inline char operator[](std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < static_size); return m_array[index]; } inline const_iterator begin() const { return m_array; } inline const_iterator end() const { return m_array + static_size; } inline static std::size_t size() { return static_size; } inline const char * data() const { return m_array; } inline std::string str() const { return std::string(m_array, static_size); } private: char m_array[static_size]; }; // matrix_handler template <typename Matrix> class matrix_handler { public: typedef Matrix result_type; static const bool interrupt = false; matrix_handler() {} result_type const& result() const { return m_matrix; } result_type const& matrix() const { return m_matrix; } result_type & matrix() { return m_matrix; } template <field F1, field F2, char D> inline bool may_update() const { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const c = m_matrix.template get<F1, F2>(); return D > c || c > '9'; } template <field F1, field F2, char V> inline void set() { static const bool in_bounds = F1 < Matrix::static_height && F2 < Matrix::static_width; typedef std::integral_constant<bool, in_bounds> in_bounds_t; set_dispatch<F1, F2, V>(in_bounds_t()); } template <field F1, field F2, char D> inline void update() { static const bool in_bounds = F1 < Matrix::static_height && F2 < Matrix::static_width; typedef std::integral_constant<bool, in_bounds> in_bounds_t; update_dispatch<F1, F2, D>(in_bounds_t()); } private: template <field F1, field F2, char V> inline void set_dispatch(std::true_type) { static const std::size_t index = F1 * Matrix::static_width + F2; BOOST_STATIC_ASSERT(index < Matrix::static_size); BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F'); m_matrix.template set<F1, F2, V>(); } template <field F1, field F2, char V> inline void set_dispatch(std::false_type) {} template <field F1, field F2, char D> inline void update_dispatch(std::true_type) { static const std::size_t index = F1 * Matrix::static_width + F2; BOOST_STATIC_ASSERT(index < Matrix::static_size); BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const c = m_matrix.template get<F1, F2>(); if ( D > c || c > '9') m_matrix.template set<F1, F2, D>(); } template <field F1, field F2, char D> inline void update_dispatch(std::false_type) {} Matrix m_matrix; }; // --------------- RUN-TIME MASK ---------------- // run-time mask template <std::size_t Height, std::size_t Width = Height> class mask { public: static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; inline mask(const char * s) { char * it = m_array; char * const last = m_array + static_size; for ( ; it != last && *s != '\0' ; ++it, ++s ) { char c = *s; check_char(c); *it = c; } if ( it != last ) { ::memset(it, '*', last - it); } } inline mask(const char * s, std::size_t count) { if ( count > static_size ) { count = static_size; } if ( count > 0 ) { std::for_each(s, s + count, check_char); ::memcpy(m_array, s, count); } if ( count < static_size ) { ::memset(m_array + count, '*', static_size - count); } } template <field F1, field F2> inline char get() const { BOOST_STATIC_ASSERT(F1 < Height && F2 < Width); static const std::size_t index = F1 * Width + F2; BOOST_STATIC_ASSERT(index < static_size); return m_array[index]; } private: static inline void check_char(char c) { bool const is_valid = c == '*' || c == 'T' || c == 'F' || ( c >= '0' && c <= '9' ); if ( !is_valid ) { BOOST_THROW_EXCEPTION(geometry::invalid_input_exception()); } } char m_array[static_size]; }; // interrupt() template <typename Mask, bool InterruptEnabled> struct interrupt_dispatch { template <field F1, field F2, char V> static inline bool apply(Mask const&) { return false; } }; template <typename Mask> struct interrupt_dispatch<Mask, true> { template <field F1, field F2, char V> static inline bool apply(Mask const& mask) { char m = mask.template get<F1, F2>(); return check_element<V>(m); } template <char V> static inline bool check_element(char m) { if ( BOOST_GEOMETRY_CONDITION(V >= '0' && V <= '9') ) { return m == 'F' || ( m < V && m >= '0' && m <= '9' ); } else if ( BOOST_GEOMETRY_CONDITION(V == 'T') ) { return m == 'F'; } return false; } }; template <typename Masks, int I = 0, int N = std::tuple_size<Masks>::value> struct interrupt_dispatch_tuple { template <field F1, field F2, char V> static inline bool apply(Masks const& masks) { typedef typename std::tuple_element<I, Masks>::type mask_type; mask_type const& mask = std::get<I>(masks); return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask) && interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks); } }; template <typename Masks, int N> struct interrupt_dispatch_tuple<Masks, N, N> { template <field F1, field F2, char V> static inline bool apply(Masks const& ) { return true; } }; template <typename ...Masks> struct interrupt_dispatch<std::tuple<Masks...>, true> { typedef std::tuple<Masks...> mask_type; template <field F1, field F2, char V> static inline bool apply(mask_type const& mask) { return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask); } }; template <field F1, field F2, char V, bool InterruptEnabled, typename Mask> inline bool interrupt(Mask const& mask) { return interrupt_dispatch<Mask, InterruptEnabled> ::template apply<F1, F2, V>(mask); } // may_update() template <typename Mask> struct may_update_dispatch { template <field F1, field F2, char D, typename Matrix> static inline bool apply(Mask const& mask, Matrix const& matrix) { BOOST_STATIC_ASSERT('0' <= D && D <= '9'); char const m = mask.template get<F1, F2>(); if ( m == 'F' ) { return true; } else if ( m == 'T' ) { char const c = matrix.template get<F1, F2>(); return c == 'F'; // if it's T or between 0 and 9, the result will be the same } else if ( m >= '0' && m <= '9' ) { char const c = matrix.template get<F1, F2>(); return D > c || c > '9'; } return false; } }; template <typename Masks, int I = 0, int N = std::tuple_size<Masks>::value> struct may_update_dispatch_tuple { template <field F1, field F2, char D, typename Matrix> static inline bool apply(Masks const& masks, Matrix const& matrix) { typedef typename std::tuple_element<I, Masks>::type mask_type; mask_type const& mask = std::get<I>(masks); return may_update_dispatch<mask_type>::template apply<F1, F2, D>(mask, matrix) || may_update_dispatch_tuple<Masks, I+1>::template apply<F1, F2, D>(masks, matrix); } }; template <typename Masks, int N> struct may_update_dispatch_tuple<Masks, N, N> { template <field F1, field F2, char D, typename Matrix> static inline bool apply(Masks const& , Matrix const& ) { return false; } }; template <typename ...Masks> struct may_update_dispatch<std::tuple<Masks...>> { typedef std::tuple<Masks...> mask_type; template <field F1, field F2, char D, typename Matrix> static inline bool apply(mask_type const& mask, Matrix const& matrix) { return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix); } }; template <field F1, field F2, char D, typename Mask, typename Matrix> inline bool may_update(Mask const& mask, Matrix const& matrix) { return may_update_dispatch<Mask> ::template apply<F1, F2, D>(mask, matrix); } // check_matrix() template <typename Mask> struct check_dispatch { template <typename Matrix> static inline bool apply(Mask const& mask, Matrix const& matrix) { return per_one<interior, interior>(mask, matrix) && per_one<interior, boundary>(mask, matrix) && per_one<interior, exterior>(mask, matrix) && per_one<boundary, interior>(mask, matrix) && per_one<boundary, boundary>(mask, matrix) && per_one<boundary, exterior>(mask, matrix) && per_one<exterior, interior>(mask, matrix) && per_one<exterior, boundary>(mask, matrix) && per_one<exterior, exterior>(mask, matrix); } template <field F1, field F2, typename Matrix> static inline bool per_one(Mask const& mask, Matrix const& matrix) { const char mask_el = mask.template get<F1, F2>(); const char el = matrix.template get<F1, F2>(); if ( mask_el == 'F' ) { return el == 'F'; } else if ( mask_el == 'T' ) { return el == 'T' || ( el >= '0' && el <= '9' ); } else if ( mask_el >= '0' && mask_el <= '9' ) { return el == mask_el; } return true; } }; template <typename Masks, int I = 0, int N = std::tuple_size<Masks>::value> struct check_dispatch_tuple { template <typename Matrix> static inline bool apply(Masks const& masks, Matrix const& matrix) { typedef typename std::tuple_element<I, Masks>::type mask_type; mask_type const& mask = std::get<I>(masks); return check_dispatch<mask_type>::apply(mask, matrix) || check_dispatch_tuple<Masks, I+1>::apply(masks, matrix); } }; template <typename Masks, int N> struct check_dispatch_tuple<Masks, N, N> { template <typename Matrix> static inline bool apply(Masks const&, Matrix const&) { return false; } }; template <typename ...Masks> struct check_dispatch<std::tuple<Masks...>> { typedef std::tuple<Masks...> mask_type; template <typename Matrix> static inline bool apply(mask_type const& mask, Matrix const& matrix) { return check_dispatch_tuple<mask_type>::apply(mask, matrix); } }; template <typename Mask, typename Matrix> inline bool check_matrix(Mask const& mask, Matrix const& matrix) { return check_dispatch<Mask>::apply(mask, matrix); } // matrix_width template <typename MatrixOrMask> struct matrix_width { static const std::size_t value = MatrixOrMask::static_width; }; template <typename Tuple, int I = 0, int N = std::tuple_size<Tuple>::value> struct matrix_width_tuple { static const std::size_t current = matrix_width<typename std::tuple_element<I, Tuple>::type>::value; static const std::size_t next = matrix_width_tuple<Tuple, I+1>::value; static const std::size_t value = current > next ? current : next; }; template <typename Tuple, int N> struct matrix_width_tuple<Tuple, N, N> { static const std::size_t value = 0; }; template <typename ...Masks> struct matrix_width<std::tuple<Masks...>> { static const std::size_t value = matrix_width_tuple<std::tuple<Masks...>>::value; }; // mask_handler template <typename Mask, bool Interrupt> class mask_handler : private matrix_handler < relate::matrix<matrix_width<Mask>::value> > { typedef matrix_handler < relate::matrix<matrix_width<Mask>::value> > base_t; public: typedef bool result_type; bool interrupt; inline explicit mask_handler(Mask const& m) : interrupt(false) , m_mask(m) {} result_type result() const { return !interrupt && check_matrix(m_mask, base_t::matrix()); } template <field F1, field F2, char D> inline bool may_update() const { return detail::relate::may_update<F1, F2, D>( m_mask, base_t::matrix() ); } template <field F1, field F2, char V> inline void set() { if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) { interrupt = true; } else { base_t::template set<F1, F2, V>(); } } template <field F1, field F2, char V> inline void update() { if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) ) { interrupt = true; } else { base_t::template update<F1, F2, V>(); } } private: Mask const& m_mask; }; // --------------- FALSE MASK ---------------- struct false_mask {}; // --------------- COMPILE-TIME MASK ---------------- // static_check_characters template <typename Seq> struct static_check_characters {}; template <char C, char ...Cs> struct static_check_characters<std::integer_sequence<char, C, Cs...>> : static_check_characters<std::integer_sequence<char, Cs...>> { typedef std::integer_sequence<char, C, Cs...> type; static const bool is_valid = (C >= '0' && C <= '9') || C == 'T' || C == 'F' || C == '*'; BOOST_GEOMETRY_STATIC_ASSERT((is_valid), "Invalid static mask character", type); }; template <char ...Cs> struct static_check_characters<std::integral_constant<char, Cs...>> {}; // static_mask template <typename Seq, std::size_t Height, std::size_t Width = Height> struct static_mask { static const std::size_t static_width = Width; static const std::size_t static_height = Height; static const std::size_t static_size = Width * Height; BOOST_STATIC_ASSERT( std::size_t(util::sequence_size<Seq>::value) == static_size); template <detail::relate::field F1, detail::relate::field F2> struct static_get { BOOST_STATIC_ASSERT(std::size_t(F1) < static_height); BOOST_STATIC_ASSERT(std::size_t(F2) < static_width); static const char value = util::sequence_element<F1 * static_width + F2, Seq>::value; }; private: // check static_mask characters enum { mask_check = sizeof(static_check_characters<Seq>) }; }; // static_should_handle_element template < typename StaticMask, field F1, field F2, bool IsSequence = util::is_sequence<StaticMask>::value > struct static_should_handle_element_dispatch { static const char mask_el = StaticMask::template static_get<F1, F2>::value; static const bool value = mask_el == 'F' || mask_el == 'T' || ( mask_el >= '0' && mask_el <= '9' ); }; template < typename Seq, field F1, field F2, std::size_t I = 0, std::size_t N = util::sequence_size<Seq>::value > struct static_should_handle_element_sequence { typedef typename util::sequence_element<I, Seq>::type StaticMask; static const bool value = static_should_handle_element_dispatch < StaticMask, F1, F2 >::value || static_should_handle_element_sequence < Seq, F1, F2, I + 1 >::value; }; template <typename Seq, field F1, field F2, std::size_t N> struct static_should_handle_element_sequence<Seq, F1, F2, N, N> { static const bool value = false; }; template <typename StaticMask, field F1, field F2> struct static_should_handle_element_dispatch<StaticMask, F1, F2, true> { static const bool value = static_should_handle_element_sequence < StaticMask, F1, F2 >::value; }; template <typename StaticMask, field F1, field F2> struct static_should_handle_element { static const bool value = static_should_handle_element_dispatch < StaticMask, F1, F2 >::value; }; // static_interrupt template < typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsSequence = util::is_sequence<StaticMask>::value > struct static_interrupt_dispatch { static const bool value = false; }; template <typename StaticMask, char V, field F1, field F2, bool IsSequence> struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence> { static const char mask_el = StaticMask::template static_get<F1, F2>::value; static const bool value = ( V >= '0' && V <= '9' ) ? ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) : ( ( V == 'T' ) ? mask_el == 'F' : false ); }; template < typename Seq, char V, field F1, field F2, std::size_t I = 0, std::size_t N = util::sequence_size<Seq>::value > struct static_interrupt_sequence { typedef typename util::sequence_element<I, Seq>::type StaticMask; static const bool value = static_interrupt_dispatch < StaticMask, V, F1, F2, true >::value && static_interrupt_sequence < Seq, V, F1, F2, I + 1 >::value; }; template <typename Seq, char V, field F1, field F2, std::size_t N> struct static_interrupt_sequence<Seq, V, F1, F2, N, N> { static const bool value = true; }; template <typename StaticMask, char V, field F1, field F2> struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, true> { static const bool value = static_interrupt_sequence < StaticMask, V, F1, F2 >::value; }; template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt> struct static_interrupt { static const bool value = static_interrupt_dispatch < StaticMask, V, F1, F2, EnableInterrupt >::value; }; // static_may_update template < typename StaticMask, char D, field F1, field F2, bool IsSequence = util::is_sequence<StaticMask>::value > struct static_may_update_dispatch { static const char mask_el = StaticMask::template static_get<F1, F2>::value; static const int version = mask_el == 'F' ? 0 : mask_el == 'T' ? 1 : mask_el >= '0' && mask_el <= '9' ? 2 : 3; // TODO: use std::enable_if_t instead of std::integral_constant template <typename Matrix> static inline bool apply(Matrix const& matrix) { return apply_dispatch(matrix, std::integral_constant<int, version>()); } // mask_el == 'F' template <typename Matrix> static inline bool apply_dispatch(Matrix const& , std::integral_constant<int, 0>) { return true; } // mask_el == 'T' template <typename Matrix> static inline bool apply_dispatch(Matrix const& matrix, std::integral_constant<int, 1>) { char const c = matrix.template get<F1, F2>(); return c == 'F'; // if it's T or between 0 and 9, the result will be the same } // mask_el >= '0' && mask_el <= '9' template <typename Matrix> static inline bool apply_dispatch(Matrix const& matrix, std::integral_constant<int, 2>) { char const c = matrix.template get<F1, F2>(); return D > c || c > '9'; } // else template <typename Matrix> static inline bool apply_dispatch(Matrix const&, std::integral_constant<int, 3>) { return false; } }; template < typename Seq, char D, field F1, field F2, std::size_t I = 0, std::size_t N = util::sequence_size<Seq>::value > struct static_may_update_sequence { typedef typename util::sequence_element<I, Seq>::type StaticMask; template <typename Matrix> static inline bool apply(Matrix const& matrix) { return static_may_update_dispatch < StaticMask, D, F1, F2 >::apply(matrix) || static_may_update_sequence < Seq, D, F1, F2, I + 1 >::apply(matrix); } }; template <typename Seq, char D, field F1, field F2, std::size_t N> struct static_may_update_sequence<Seq, D, F1, F2, N, N> { template <typename Matrix> static inline bool apply(Matrix const& /*matrix*/) { return false; } }; template <typename StaticMask, char D, field F1, field F2> struct static_may_update_dispatch<StaticMask, D, F1, F2, true> { template <typename Matrix> static inline bool apply(Matrix const& matrix) { return static_may_update_sequence < StaticMask, D, F1, F2 >::apply(matrix); } }; template <typename StaticMask, char D, field F1, field F2> struct static_may_update { template <typename Matrix> static inline bool apply(Matrix const& matrix) { return static_may_update_dispatch < StaticMask, D, F1, F2 >::apply(matrix); } }; // static_check_matrix template < typename StaticMask, bool IsSequence = util::is_sequence<StaticMask>::value > struct static_check_dispatch { template <typename Matrix> static inline bool apply(Matrix const& matrix) { return per_one<interior, interior>::apply(matrix) && per_one<interior, boundary>::apply(matrix) && per_one<interior, exterior>::apply(matrix) && per_one<boundary, interior>::apply(matrix) && per_one<boundary, boundary>::apply(matrix) && per_one<boundary, exterior>::apply(matrix) && per_one<exterior, interior>::apply(matrix) && per_one<exterior, boundary>::apply(matrix) && per_one<exterior, exterior>::apply(matrix); } template <field F1, field F2> struct per_one { static const char mask_el = StaticMask::template static_get<F1, F2>::value; static const int version = mask_el == 'F' ? 0 : mask_el == 'T' ? 1 : mask_el >= '0' && mask_el <= '9' ? 2 : 3; // TODO: use std::enable_if_t instead of std::integral_constant template <typename Matrix> static inline bool apply(Matrix const& matrix) { const char el = matrix.template get<F1, F2>(); return apply_dispatch(el, std::integral_constant<int, version>()); } // mask_el == 'F' static inline bool apply_dispatch(char el, std::integral_constant<int, 0>) { return el == 'F'; } // mask_el == 'T' static inline bool apply_dispatch(char el, std::integral_constant<int, 1>) { return el == 'T' || ( el >= '0' && el <= '9' ); } // mask_el >= '0' && mask_el <= '9' static inline bool apply_dispatch(char el, std::integral_constant<int, 2>) { return el == mask_el; } // else static inline bool apply_dispatch(char /*el*/, std::integral_constant<int, 3>) { return true; } }; }; template < typename Seq, std::size_t I = 0, std::size_t N = util::sequence_size<Seq>::value > struct static_check_sequence { typedef typename util::sequence_element<I, Seq>::type StaticMask; template <typename Matrix> static inline bool apply(Matrix const& matrix) { return static_check_dispatch < StaticMask >::apply(matrix) || static_check_sequence < Seq, I + 1 >::apply(matrix); } }; template <typename Seq, std::size_t N> struct static_check_sequence<Seq, N, N> { template <typename Matrix> static inline bool apply(Matrix const& /*matrix*/) { return false; } }; template <typename StaticMask> struct static_check_dispatch<StaticMask, true> { template <typename Matrix> static inline bool apply(Matrix const& matrix) { return static_check_sequence < StaticMask >::apply(matrix); } }; template <typename StaticMask> struct static_check_matrix { template <typename Matrix> static inline bool apply(Matrix const& matrix) { return static_check_dispatch < StaticMask >::apply(matrix); } }; // static_mask_handler template <typename StaticMask, bool Interrupt> class static_mask_handler : private matrix_handler< matrix<3> > { typedef matrix_handler< relate::matrix<3> > base_type; public: typedef bool result_type; bool interrupt; inline static_mask_handler() : interrupt(false) {} inline explicit static_mask_handler(StaticMask const& /*dummy*/) : interrupt(false) {} result_type result() const { return (!Interrupt || !interrupt) && static_check_matrix<StaticMask>::apply(base_type::matrix()); } template <field F1, field F2, char D> inline bool may_update() const { return static_may_update<StaticMask, D, F1, F2>:: apply(base_type::matrix()); } template <field F1, field F2> static inline bool expects() { return static_should_handle_element<StaticMask, F1, F2>::value; } template <field F1, field F2, char V> inline void set() { static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; static const int version = interrupt_c ? 0 : should_handle ? 1 : 2; set_dispatch<F1, F2, V>(integral_constant<int, version>()); } template <field F1, field F2, char V> inline void update() { static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value; static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value; static const int version = interrupt_c ? 0 : should_handle ? 1 : 2; update_dispatch<F1, F2, V>(integral_constant<int, version>()); } private: // Interrupt && interrupt template <field F1, field F2, char V> inline void set_dispatch(integral_constant<int, 0>) { interrupt = true; } // else should_handle template <field F1, field F2, char V> inline void set_dispatch(integral_constant<int, 1>) { base_type::template set<F1, F2, V>(); } // else template <field F1, field F2, char V> inline void set_dispatch(integral_constant<int, 2>) {} // Interrupt && interrupt template <field F1, field F2, char V> inline void update_dispatch(integral_constant<int, 0>) { interrupt = true; } // else should_handle template <field F1, field F2, char V> inline void update_dispatch(integral_constant<int, 1>) { base_type::template update<F1, F2, V>(); } // else template <field F1, field F2, char V> inline void update_dispatch(integral_constant<int, 2>) {} }; // --------------- UTIL FUNCTIONS ---------------- // set template <field F1, field F2, char V, typename Result> inline void set(Result & res) { res.template set<F1, F2, V>(); } template <field F1, field F2, char V, bool Transpose> struct set_dispatch { template <typename Result> static inline void apply(Result & res) { res.template set<F1, F2, V>(); } }; template <field F1, field F2, char V> struct set_dispatch<F1, F2, V, true> { template <typename Result> static inline void apply(Result & res) { res.template set<F2, F1, V>(); } }; template <field F1, field F2, char V, bool Transpose, typename Result> inline void set(Result & res) { set_dispatch<F1, F2, V, Transpose>::apply(res); } // update template <field F1, field F2, char D, typename Result> inline void update(Result & res) { res.template update<F1, F2, D>(); } template <field F1, field F2, char D, bool Transpose> struct update_result_dispatch { template <typename Result> static inline void apply(Result & res) { update<F1, F2, D>(res); } }; template <field F1, field F2, char D> struct update_result_dispatch<F1, F2, D, true> { template <typename Result> static inline void apply(Result & res) { update<F2, F1, D>(res); } }; template <field F1, field F2, char D, bool Transpose, typename Result> inline void update(Result & res) { update_result_dispatch<F1, F2, D, Transpose>::apply(res); } // may_update template <field F1, field F2, char D, typename Result> inline bool may_update(Result const& res) { return res.template may_update<F1, F2, D>(); } template <field F1, field F2, char D, bool Transpose> struct may_update_result_dispatch { template <typename Result> static inline bool apply(Result const& res) { return may_update<F1, F2, D>(res); } }; template <field F1, field F2, char D> struct may_update_result_dispatch<F1, F2, D, true> { template <typename Result> static inline bool apply(Result const& res) { return may_update<F2, F1, D>(res); } }; template <field F1, field F2, char D, bool Transpose, typename Result> inline bool may_update(Result const& res) { return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res); } // result_dimension template <typename Geometry> struct result_dimension { BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0); static const char value = ( geometry::dimension<Geometry>::value <= 9 ) ? ( '0' + geometry::dimension<Geometry>::value ) : 'T'; }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP detail/relate/areal_areal.hpp 0000644 00000102056 15125631656 0012241 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018, 2019. // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP #include <boost/geometry/core/topological_dimension.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/detail/single_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/turns.hpp> #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // WARNING! // TODO: In the worst case calling this Pred in a loop for MultiPolygon/MultiPolygon may take O(NM) // Use the rtree in this case! // may be used to set EI and EB for an Areal geometry for which no turns were generated template < typename OtherAreal, typename Result, typename PointInArealStrategy, bool TransposeResult > class no_turns_aa_pred { public: no_turns_aa_pred(OtherAreal const& other_areal, Result & res, PointInArealStrategy const& point_in_areal_strategy) : m_result(res) , m_point_in_areal_strategy(point_in_areal_strategy) , m_other_areal(other_areal) , m_flags(0) { // check which relations must be analysed if ( ! may_update<interior, interior, '2', TransposeResult>(m_result) && ! may_update<boundary, interior, '1', TransposeResult>(m_result) && ! may_update<exterior, interior, '2', TransposeResult>(m_result) ) { m_flags |= 1; } if ( ! may_update<interior, exterior, '2', TransposeResult>(m_result) && ! may_update<boundary, exterior, '1', TransposeResult>(m_result) ) { m_flags |= 2; } } template <typename Areal> bool operator()(Areal const& areal) { using detail::within::point_in_geometry; // if those flags are set nothing will change if ( m_flags == 3 ) { return false; } typedef typename geometry::point_type<Areal>::type point_type; point_type pt; bool const ok = boost::geometry::point_on_border(pt, areal); // TODO: for now ignore, later throw an exception? if ( !ok ) { return true; } // check if the areal is inside the other_areal // TODO: This is O(N) // Run in a loop O(NM) - optimize! int const pig = point_in_geometry(pt, m_other_areal, m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT( pig != 0 ); // inside if ( pig > 0 ) { update<interior, interior, '2', TransposeResult>(m_result); update<boundary, interior, '1', TransposeResult>(m_result); update<exterior, interior, '2', TransposeResult>(m_result); m_flags |= 1; // TODO: OPTIMIZE! // Only the interior rings of other ONE single geometry must be checked // NOT all geometries // Check if any interior ring is outside ring_identifier ring_id(0, -1, 0); std::size_t const irings_count = geometry::num_interior_rings(areal); for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ; ++ring_id.ring_index ) { typename detail::sub_range_return_type<Areal const>::type range_ref = detail::sub_range(areal, ring_id); if ( boost::empty(range_ref) ) { // TODO: throw exception? continue; // ignore } // TODO: O(N) // Optimize! int const hpig = point_in_geometry(range::front(range_ref), m_other_areal, m_point_in_areal_strategy); // hole outside if ( hpig < 0 ) { update<interior, exterior, '2', TransposeResult>(m_result); update<boundary, exterior, '1', TransposeResult>(m_result); m_flags |= 2; break; } } } // outside else { update<interior, exterior, '2', TransposeResult>(m_result); update<boundary, exterior, '1', TransposeResult>(m_result); m_flags |= 2; // Check if any interior ring is inside ring_identifier ring_id(0, -1, 0); std::size_t const irings_count = geometry::num_interior_rings(areal); for ( ; static_cast<std::size_t>(ring_id.ring_index) < irings_count ; ++ring_id.ring_index ) { typename detail::sub_range_return_type<Areal const>::type range_ref = detail::sub_range(areal, ring_id); if ( boost::empty(range_ref) ) { // TODO: throw exception? continue; // ignore } // TODO: O(N) // Optimize! int const hpig = point_in_geometry(range::front(range_ref), m_other_areal, m_point_in_areal_strategy); // hole inside if ( hpig > 0 ) { update<interior, interior, '2', TransposeResult>(m_result); update<boundary, interior, '1', TransposeResult>(m_result); update<exterior, interior, '2', TransposeResult>(m_result); m_flags |= 1; break; } } } return m_flags != 3 && !m_result.interrupt; } private: Result & m_result; PointInArealStrategy const& m_point_in_areal_strategy; OtherAreal const& m_other_areal; int m_flags; }; // The implementation of an algorithm calculating relate() for A/A template <typename Geometry1, typename Geometry2> struct areal_areal { // check Linear / Areal BOOST_STATIC_ASSERT(topological_dimension<Geometry1>::value == 2 && topological_dimension<Geometry2>::value == 2); static const bool interruption_enabled = true; typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; template <typename Result, typename IntersectionStrategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, IntersectionStrategy const& intersection_strategy) { // TODO: If Areal geometry may have infinite size, change the following line: // The result should be FFFFFFFFF relate::set<exterior, exterior, result_dimension<Geometry2>::value>(result);// FFFFFFFFd, d in [1,9] or T if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; // get and analyse turns typedef typename turns::get_turns < Geometry1, Geometry2 >::template turn_info_type<IntersectionStrategy>::type turn_type; std::vector<turn_type> turns; interrupt_policy_areal_areal<Result> interrupt_policy(geometry1, geometry2, result); turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; typedef typename IntersectionStrategy::cs_tag cs_tag; typedef typename IntersectionStrategy::template point_in_geometry_strategy < Geometry1, Geometry2 >::type point_in_areal_strategy12_type; point_in_areal_strategy12_type point_in_areal_strategy12 = intersection_strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(); typedef typename IntersectionStrategy::template point_in_geometry_strategy < Geometry2, Geometry1 >::type point_in_areal_strategy21_type; point_in_areal_strategy21_type point_in_areal_strategy21 = intersection_strategy.template get_point_in_geometry_strategy<Geometry2, Geometry1>(); no_turns_aa_pred<Geometry2, Result, point_in_areal_strategy12_type, false> pred1(geometry2, result, point_in_areal_strategy12); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; no_turns_aa_pred<Geometry1, Result, point_in_areal_strategy21_type, true> pred2(geometry1, result, point_in_areal_strategy21); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; if ( turns.empty() ) return; if ( may_update<interior, interior, '2'>(result) || may_update<interior, exterior, '2'>(result) || may_update<boundary, interior, '1'>(result) || may_update<boundary, exterior, '1'>(result) || may_update<exterior, interior, '2'>(result) ) { // sort turns typedef turns::less<0, turns::less_op_areal_areal<0>, cs_tag> less; std::sort(turns.begin(), turns.end(), less()); /*if ( may_update<interior, exterior, '2'>(result) || may_update<boundary, exterior, '1'>(result) || may_update<boundary, interior, '1'>(result) || may_update<exterior, interior, '2'>(result) )*/ { // analyse sorted turns turns_analyser<turn_type, 0> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end(), point_in_areal_strategy12.get_equals_point_point_strategy()); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; } if ( may_update<interior, interior, '2'>(result) || may_update<interior, exterior, '2'>(result) || may_update<boundary, interior, '1'>(result) || may_update<boundary, exterior, '1'>(result) || may_update<exterior, interior, '2'>(result) ) { // analyse rings for which turns were not generated // or only i/i or u/u was generated uncertain_rings_analyser<0, Result, Geometry1, Geometry2, point_in_areal_strategy12_type> rings_analyser(result, geometry1, geometry2, point_in_areal_strategy12); analyse_uncertain_rings<0>::apply(rings_analyser, turns.begin(), turns.end()); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; } } if ( may_update<interior, interior, '2', true>(result) || may_update<interior, exterior, '2', true>(result) || may_update<boundary, interior, '1', true>(result) || may_update<boundary, exterior, '1', true>(result) || may_update<exterior, interior, '2', true>(result) ) { // sort turns typedef turns::less<1, turns::less_op_areal_areal<1>, cs_tag> less; std::sort(turns.begin(), turns.end(), less()); /*if ( may_update<interior, exterior, '2', true>(result) || may_update<boundary, exterior, '1', true>(result) || may_update<boundary, interior, '1', true>(result) || may_update<exterior, interior, '2', true>(result) )*/ { // analyse sorted turns turns_analyser<turn_type, 1> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end(), point_in_areal_strategy21.get_equals_point_point_strategy()); if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; } if ( may_update<interior, interior, '2', true>(result) || may_update<interior, exterior, '2', true>(result) || may_update<boundary, interior, '1', true>(result) || may_update<boundary, exterior, '1', true>(result) || may_update<exterior, interior, '2', true>(result) ) { // analyse rings for which turns were not generated // or only i/i or u/u was generated uncertain_rings_analyser<1, Result, Geometry2, Geometry1, point_in_areal_strategy21_type> rings_analyser(result, geometry2, geometry1, point_in_areal_strategy21); analyse_uncertain_rings<1>::apply(rings_analyser, turns.begin(), turns.end()); //if ( result.interrupt ) // return; } } } // interrupt policy which may be passed to get_turns to interrupt the analysis // based on the info in the passed result/mask template <typename Result> class interrupt_policy_areal_areal { public: static bool const enabled = true; interrupt_policy_areal_areal(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) : m_result(result) , m_geometry1(geometry1) , m_geometry2(geometry2) {} template <typename Range> inline bool apply(Range const& turns) { typedef typename boost::range_iterator<Range const>::type iterator; for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) { per_turn<0>(*it); per_turn<1>(*it); } return m_result.interrupt; } private: template <std::size_t OpId, typename Turn> inline void per_turn(Turn const& turn) { //static const std::size_t other_op_id = (OpId + 1) % 2; static const bool transpose_result = OpId != 0; overlay::operation_type const op = turn.operations[OpId].operation; if ( op == overlay::operation_union ) { // ignore u/u /*if ( turn.operations[other_op_id].operation != overlay::operation_union ) { update<interior, exterior, '2', transpose_result>(m_result); update<boundary, exterior, '1', transpose_result>(m_result); }*/ update<boundary, boundary, '0', transpose_result>(m_result); } else if ( op == overlay::operation_intersection ) { // ignore i/i /*if ( turn.operations[other_op_id].operation != overlay::operation_intersection ) { // not correct e.g. for G1 touching G2 in a point where a hole is touching the exterior ring // in this case 2 turns i/... and u/u will be generated for this IP //update<interior, interior, '2', transpose_result>(m_result); //update<boundary, interior, '1', transpose_result>(m_result); }*/ update<boundary, boundary, '0', transpose_result>(m_result); } else if ( op == overlay::operation_continue ) { update<boundary, boundary, '1', transpose_result>(m_result); update<interior, interior, '2', transpose_result>(m_result); } else if ( op == overlay::operation_blocked ) { update<boundary, boundary, '1', transpose_result>(m_result); update<interior, exterior, '2', transpose_result>(m_result); } } Result & m_result; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; }; // This analyser should be used like Input or SinglePass Iterator // IMPORTANT! It should be called also for the end iterator - last template <typename TurnInfo, std::size_t OpId> class turns_analyser { typedef typename TurnInfo::point_type turn_point_type; static const std::size_t op_id = OpId; static const std::size_t other_op_id = (OpId + 1) % 2; static const bool transpose_result = OpId != 0; public: turns_analyser() : m_previous_turn_ptr(0) , m_previous_operation(overlay::operation_none) , m_enter_detected(false) , m_exit_detected(false) {} template <typename Result, typename TurnIt, typename EqPPStrategy> void apply(Result & result, TurnIt it, EqPPStrategy const& strategy) { //BOOST_GEOMETRY_ASSERT( it != last ); overlay::operation_type const op = it->operations[op_id].operation; if ( op != overlay::operation_union && op != overlay::operation_intersection && op != overlay::operation_blocked && op != overlay::operation_continue ) { return; } segment_identifier const& seg_id = it->operations[op_id].seg_id; //segment_identifier const& other_id = it->operations[other_op_id].seg_id; const bool first_in_range = m_seg_watcher.update(seg_id); if ( m_previous_turn_ptr ) { if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ ) { // real exit point - may be multiple if ( first_in_range || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) ) { update_exit(result); m_exit_detected = false; } // fake exit point, reset state else if ( op != overlay::operation_union ) { m_exit_detected = false; } } /*else*/ if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ ) { // real entry point if ( first_in_range || ! turn_on_the_same_ip<op_id>(*m_previous_turn_ptr, *it, strategy) ) { update_enter(result); m_enter_detected = false; } // fake entry point, reset state else if ( op != overlay::operation_intersection ) { m_enter_detected = false; } } } if ( op == overlay::operation_union ) { // already set in interrupt policy //update<boundary, boundary, '0', transpose_result>(m_result); // ignore u/u //if ( it->operations[other_op_id].operation != overlay::operation_union ) { m_exit_detected = true; } } else if ( op == overlay::operation_intersection ) { // ignore i/i if ( it->operations[other_op_id].operation != overlay::operation_intersection ) { // this was set in the interrupt policy but it was wrong // also here it's wrong since it may be a fake entry point //update<interior, interior, '2', transpose_result>(result); // already set in interrupt policy //update<boundary, boundary, '0', transpose_result>(result); m_enter_detected = true; } } else if ( op == overlay::operation_blocked ) { // already set in interrupt policy } else // if ( op == overlay::operation_continue ) { // already set in interrupt policy } // store ref to previously analysed (valid) turn m_previous_turn_ptr = boost::addressof(*it); // and previously analysed (valid) operation m_previous_operation = op; } // it == last template <typename Result> void apply(Result & result) { //BOOST_GEOMETRY_ASSERT( first != last ); if ( m_exit_detected /*m_previous_operation == overlay::operation_union*/ ) { update_exit(result); m_exit_detected = false; } if ( m_enter_detected /*m_previous_operation == overlay::operation_intersection*/ ) { update_enter(result); m_enter_detected = false; } } template <typename Result> static inline void update_exit(Result & result) { update<interior, exterior, '2', transpose_result>(result); update<boundary, exterior, '1', transpose_result>(result); } template <typename Result> static inline void update_enter(Result & result) { update<interior, interior, '2', transpose_result>(result); update<boundary, interior, '1', transpose_result>(result); update<exterior, interior, '2', transpose_result>(result); } private: segment_watcher<same_ring> m_seg_watcher; TurnInfo * m_previous_turn_ptr; overlay::operation_type m_previous_operation; bool m_enter_detected; bool m_exit_detected; }; // call analyser.apply() for each turn in range // IMPORTANT! The analyser is also called for the end iterator - last template < typename Result, typename Analyser, typename TurnIt, typename EqPPStrategy > static inline void analyse_each_turn(Result & res, Analyser & analyser, TurnIt first, TurnIt last, EqPPStrategy const& strategy) { if ( first == last ) return; for ( TurnIt it = first ; it != last ; ++it ) { analyser.apply(res, it, strategy); if ( BOOST_GEOMETRY_CONDITION(res.interrupt) ) return; } analyser.apply(res); } template < std::size_t OpId, typename Result, typename Geometry, typename OtherGeometry, typename PointInArealStrategy > class uncertain_rings_analyser { static const bool transpose_result = OpId != 0; static const int other_id = (OpId + 1) % 2; public: inline uncertain_rings_analyser(Result & result, Geometry const& geom, OtherGeometry const& other_geom, PointInArealStrategy const& point_in_areal_strategy) : geometry(geom) , other_geometry(other_geom) , interrupt(result.interrupt) // just in case, could be false as well , m_result(result) , m_point_in_areal_strategy(point_in_areal_strategy) , m_flags(0) { // check which relations must be analysed // NOTE: 1 and 4 could probably be connected if ( ! may_update<interior, interior, '2', transpose_result>(m_result) ) { m_flags |= 1; } if ( ! may_update<interior, exterior, '2', transpose_result>(m_result) && ! may_update<boundary, exterior, '1', transpose_result>(m_result) ) { m_flags |= 2; } if ( ! may_update<boundary, interior, '1', transpose_result>(m_result) && ! may_update<exterior, interior, '2', transpose_result>(m_result) ) { m_flags |= 4; } } inline void no_turns(segment_identifier const& seg_id) { // if those flags are set nothing will change if ( m_flags == 7 ) { return; } typename detail::sub_range_return_type<Geometry const>::type range_ref = detail::sub_range(geometry, seg_id); if ( boost::empty(range_ref) ) { // TODO: throw an exception? return; // ignore } // TODO: possible optimization // if the range is an interior ring we may use other IPs generated for this single geometry // to know which other single geometries should be checked // TODO: optimize! e.g. use spatial index // O(N) - running it in a loop gives O(NM) using detail::within::point_in_geometry; int const pig = point_in_geometry(range::front(range_ref), other_geometry, m_point_in_areal_strategy); //BOOST_GEOMETRY_ASSERT(pig != 0); if ( pig > 0 ) { update<interior, interior, '2', transpose_result>(m_result); m_flags |= 1; update<boundary, interior, '1', transpose_result>(m_result); update<exterior, interior, '2', transpose_result>(m_result); m_flags |= 4; } else { update<boundary, exterior, '1', transpose_result>(m_result); update<interior, exterior, '2', transpose_result>(m_result); m_flags |= 2; } // TODO: break if all things are set // also some of them could be checked outside, before the analysis // In this case we shouldn't relay just on dummy flags // Flags should be initialized with proper values // or the result should be checked directly // THIS IS ALSO TRUE FOR OTHER ANALYSERS! in L/L and L/A interrupt = m_flags == 7 || m_result.interrupt; } template <typename TurnIt> inline void turns(TurnIt first, TurnIt last) { // if those flags are set nothing will change if ( (m_flags & 6) == 6 ) { return; } bool found_ii = false; bool found_uu = false; for ( TurnIt it = first ; it != last ; ++it ) { if ( it->operations[0].operation == overlay::operation_intersection && it->operations[1].operation == overlay::operation_intersection ) { found_ii = true; } else if ( it->operations[0].operation == overlay::operation_union && it->operations[1].operation == overlay::operation_union ) { found_uu = true; } else // ignore { return; // don't interrupt } } // only i/i was generated for this ring if ( found_ii ) { update<interior, interior, '2', transpose_result>(m_result); m_flags |= 1; //update<boundary, boundary, '0', transpose_result>(m_result); update<boundary, interior, '1', transpose_result>(m_result); update<exterior, interior, '2', transpose_result>(m_result); m_flags |= 4; } // only u/u was generated for this ring if ( found_uu ) { update<boundary, exterior, '1', transpose_result>(m_result); update<interior, exterior, '2', transpose_result>(m_result); m_flags |= 2; } interrupt = m_flags == 7 || m_result.interrupt; // interrupt if the result won't be changed in the future } Geometry const& geometry; OtherGeometry const& other_geometry; bool interrupt; private: Result & m_result; PointInArealStrategy const& m_point_in_areal_strategy; int m_flags; }; template <std::size_t OpId> class analyse_uncertain_rings { public: template <typename Analyser, typename TurnIt> static inline void apply(Analyser & analyser, TurnIt first, TurnIt last) { if ( first == last ) return; for_preceding_rings(analyser, *first); //analyser.per_turn(*first); TurnIt prev = first; for ( ++first ; first != last ; ++first, ++prev ) { // same multi if ( prev->operations[OpId].seg_id.multi_index == first->operations[OpId].seg_id.multi_index ) { // same ring if ( prev->operations[OpId].seg_id.ring_index == first->operations[OpId].seg_id.ring_index ) { //analyser.per_turn(*first); } // same multi, next ring else { //analyser.end_ring(*prev); analyser.turns(prev, first); //if ( prev->operations[OpId].seg_id.ring_index + 1 // < first->operations[OpId].seg_id.ring_index) { for_no_turns_rings(analyser, *first, prev->operations[OpId].seg_id.ring_index + 1, first->operations[OpId].seg_id.ring_index); } //analyser.per_turn(*first); } } // next multi else { //analyser.end_ring(*prev); analyser.turns(prev, first); for_following_rings(analyser, *prev); for_preceding_rings(analyser, *first); //analyser.per_turn(*first); } if ( analyser.interrupt ) { return; } } //analyser.end_ring(*prev); analyser.turns(prev, first); // first == last for_following_rings(analyser, *prev); } private: template <typename Analyser, typename Turn> static inline void for_preceding_rings(Analyser & analyser, Turn const& turn) { segment_identifier const& seg_id = turn.operations[OpId].seg_id; for_no_turns_rings(analyser, turn, -1, seg_id.ring_index); } template <typename Analyser, typename Turn> static inline void for_following_rings(Analyser & analyser, Turn const& turn) { segment_identifier const& seg_id = turn.operations[OpId].seg_id; signed_size_type count = boost::numeric_cast<signed_size_type>( geometry::num_interior_rings( detail::single_geometry(analyser.geometry, seg_id))); for_no_turns_rings(analyser, turn, seg_id.ring_index + 1, count); } template <typename Analyser, typename Turn> static inline void for_no_turns_rings(Analyser & analyser, Turn const& turn, signed_size_type first, signed_size_type last) { segment_identifier seg_id = turn.operations[OpId].seg_id; for ( seg_id.ring_index = first ; seg_id.ring_index < last ; ++seg_id.ring_index ) { analyser.no_turns(seg_id); } } }; }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_AREAL_AREAL_HPP detail/relate/interface.hpp 0000644 00000030015 15125631656 0011744 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP #include <tuple> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/relate/de9im.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/topological_dimension.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/relate.hpp> #include <boost/geometry/util/sequence.hpp> #include <boost/geometry/util/type_traits.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // is_generic allows dispatch::relate to generate compile-time error template <typename Geometry1, typename Geometry2> struct is_generic { static const bool value = (util::is_polysegmental<Geometry1>::value && util::is_polysegmental<Geometry2>::value) || (util::is_point<Geometry1>::value && util::is_polysegmental<Geometry2>::value) || (util::is_polysegmental<Geometry1>::value && util::is_point<Geometry2>::value); }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry1, typename Geometry2, typename Tag1 = typename geometry::tag<Geometry1>::type, typename Tag2 = typename geometry::tag<Geometry2>::type, int TopDim1 = geometry::topological_dimension<Geometry1>::value, int TopDim2 = geometry::topological_dimension<Geometry2>::value, bool IsGeneric = detail::relate::is_generic<Geometry1, Geometry2>::value > struct relate : not_implemented<Tag1, Tag2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template <typename Geometry1, typename Geometry2> struct interruption_enabled { static const bool value = dispatch::relate<Geometry1, Geometry2>::interruption_enabled; }; template <typename Geometry1, typename Geometry2, typename Result> struct result_handler_type : not_implemented<Result> {}; template <typename Geometry1, typename Geometry2> struct result_handler_type<Geometry1, Geometry2, geometry::de9im::mask> { typedef mask_handler < geometry::de9im::mask, interruption_enabled < Geometry1, Geometry2 >::value > type; }; template <typename Geometry1, typename Geometry2, typename ...Masks> struct result_handler_type<Geometry1, Geometry2, std::tuple<Masks...>> { typedef mask_handler < std::tuple<Masks...>, interruption_enabled < Geometry1, Geometry2 >::value > type; }; template <typename Geometry1, typename Geometry2, char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE> struct result_handler_type < Geometry1, Geometry2, geometry::de9im::static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE> > { typedef static_mask_handler < geometry::de9im::static_mask<II, IB, IE, BI, BB, BE, EI, EB, EE>, interruption_enabled < Geometry1, Geometry2 >::value > type; }; template <typename Geometry1, typename Geometry2, typename ...StaticMasks> struct result_handler_type<Geometry1, Geometry2, util::type_sequence<StaticMasks...>> { typedef static_mask_handler < util::type_sequence<StaticMasks...>, interruption_enabled < Geometry1, Geometry2 >::value > type; }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL namespace resolve_strategy { struct relate { template <typename Geometry1, typename Geometry2, typename ResultHandler, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, ResultHandler & handler, Strategy const& strategy) { dispatch::relate < Geometry1, Geometry2 >::apply(geometry1, geometry2, handler, strategy); } template <typename Geometry1, typename Geometry2, typename ResultHandler> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, ResultHandler & handler, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; dispatch::relate < Geometry1, Geometry2 >::apply(geometry1, geometry2, handler, strategy_type()); } }; } // resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct relate { template <typename Mask, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); assert_dimension_equal<Geometry1, Geometry2>(); typename detail::relate::result_handler_type < Geometry1, Geometry2, Mask >::type handler(mask); resolve_strategy::relate::apply(geometry1, geometry2, handler, strategy); return handler.result(); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct relate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Mask, typename Strategy> struct visitor : boost::static_visitor<bool> { Geometry2 const& m_geometry2; Mask const& m_mask; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy) : m_geometry2(geometry2), m_mask(mask), m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return relate<Geometry1, Geometry2> ::apply(geometry1, m_geometry2, m_mask, m_strategy); } }; template <typename Mask, typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy) { return boost::apply_visitor(visitor<Mask, Strategy>(geometry2, mask, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct relate<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Mask, typename Strategy> struct visitor : boost::static_visitor<bool> { Geometry1 const& m_geometry1; Mask const& m_mask; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Mask const& mask, Strategy const& strategy) : m_geometry1(geometry1), m_mask(mask), m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return relate<Geometry1, Geometry2> ::apply(m_geometry1, geometry2, m_mask, m_strategy); } }; template <typename Mask, typename Strategy> static inline bool apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Mask const& mask, Strategy const& strategy) { return boost::apply_visitor(visitor<Mask, Strategy>(geometry1, mask, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct relate< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Mask, typename Strategy> struct visitor : boost::static_visitor<bool> { Mask const& m_mask; Strategy const& m_strategy; visitor(Mask const& mask, Strategy const& strategy) : m_mask(mask), m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return relate<Geometry1, Geometry2> ::apply(geometry1, geometry2, m_mask, m_strategy); } }; template <typename Mask, typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Mask const& mask, Strategy const& strategy) { return boost::apply_visitor(visitor<Mask, Strategy>(mask, strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief Checks relation between a pair of geometries defined by a mask. \ingroup relate \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Mask An intersection model Mask type. \tparam Strategy \tparam_strategy{Relate} \param geometry1 \param_geometry \param geometry2 \param_geometry \param mask An intersection model mask object. \param strategy \param_strategy{relate} \return true if the relation is compatible with the mask, false otherwise. \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/relate.qbk]} */ template <typename Geometry1, typename Geometry2, typename Mask, typename Strategy> inline bool relate(Geometry1 const& geometry1, Geometry2 const& geometry2, Mask const& mask, Strategy const& strategy) { return resolve_variant::relate < Geometry1, Geometry2 >::apply(geometry1, geometry2, mask, strategy); } /*! \brief Checks relation between a pair of geometries defined by a mask. \ingroup relate \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Mask An intersection model Mask type. \param geometry1 \param_geometry \param geometry2 \param_geometry \param mask An intersection model mask object. \return true if the relation is compatible with the mask, false otherwise. \qbk{[include reference/algorithms/relate.qbk]} */ template <typename Geometry1, typename Geometry2, typename Mask> inline bool relate(Geometry1 const& geometry1, Geometry2 const& geometry2, Mask const& mask) { return resolve_variant::relate < Geometry1, Geometry2 >::apply(geometry1, geometry2, mask, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP detail/relate/topology_check.hpp 0000644 00000022670 15125631656 0013025 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/util/has_nan_coordinate.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // TODO: change the name for e.g. something with the word "exterior" template <typename Geometry, typename EqPPStrategy, typename Tag = typename geometry::tag<Geometry>::type> struct topology_check : not_implemented<Tag> {}; //template <typename Point> //struct topology_check<Point, point_tag> //{ // static const char interior = '0'; // static const char boundary = 'F'; // // static const bool has_interior = true; // static const bool has_boundary = false; // // topology_check(Point const&) {} // template <typename IgnoreBoundaryPoint> // topology_check(Point const&, IgnoreBoundaryPoint const&) {} //}; template <typename Linestring, typename EqPPStrategy> struct topology_check<Linestring, EqPPStrategy, linestring_tag> { static const char interior = '1'; static const char boundary = '0'; topology_check(Linestring const& ls) : m_ls(ls) , m_is_initialized(false) {} bool has_interior() const { init(); return m_has_interior; } bool has_boundary() const { init(); return m_has_boundary; } /*template <typename Point> bool check_boundary_point(Point const& point) const { init(); return m_has_boundary && ( equals::equals_point_point(point, range::front(m_ls)) || equals::equals_point_point(point, range::back(m_ls)) ); }*/ template <typename Visitor> void for_each_boundary_point(Visitor & visitor) const { init(); if (m_has_boundary) { if (visitor.apply(range::front(m_ls))) visitor.apply(range::back(m_ls)); } } private: void init() const { if (m_is_initialized) return; std::size_t count = boost::size(m_ls); m_has_interior = count > 0; // NOTE: Linestring with all points equal is treated as 1d linear ring m_has_boundary = count > 1 && ! detail::equals::equals_point_point(range::front(m_ls), range::back(m_ls), EqPPStrategy()); m_is_initialized = true; } Linestring const& m_ls; mutable bool m_is_initialized; mutable bool m_has_interior; mutable bool m_has_boundary; }; template <typename MultiLinestring, typename EqPPStrategy> struct topology_check<MultiLinestring, EqPPStrategy, multi_linestring_tag> { static const char interior = '1'; static const char boundary = '0'; topology_check(MultiLinestring const& mls) : m_mls(mls) , m_is_initialized(false) {} bool has_interior() const { init(); return m_has_interior; } bool has_boundary() const { init(); return m_has_boundary; } template <typename Point> bool check_boundary_point(Point const& point) const { init(); if (! m_has_boundary) return false; std::size_t count = count_equal(m_endpoints.begin(), m_endpoints.end(), point); return count % 2 != 0; // odd count -> boundary } template <typename Visitor> void for_each_boundary_point(Visitor & visitor) const { init(); if (m_has_boundary) { for_each_boundary_point(m_endpoints.begin(), m_endpoints.end(), visitor); } } private: typedef geometry::less<void, -1, typename EqPPStrategy::cs_tag> less_type; void init() const { if (m_is_initialized) return; m_endpoints.reserve(boost::size(m_mls) * 2); m_has_interior = false; typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator; for ( ls_iterator it = boost::begin(m_mls) ; it != boost::end(m_mls) ; ++it ) { typename boost::range_reference<MultiLinestring const>::type ls = *it; std::size_t count = boost::size(ls); if (count > 0) { m_has_interior = true; } if (count > 1) { typedef typename boost::range_reference < typename boost::range_value<MultiLinestring const>::type const >::type point_reference; point_reference front_pt = range::front(ls); point_reference back_pt = range::back(ls); // don't store boundaries of linear rings, this doesn't change anything if (! equals::equals_point_point(front_pt, back_pt, EqPPStrategy())) { // do not add points containing NaN coordinates // because they cannot be reasonably compared, e.g. with MSVC // an assertion failure is reported in std::equal_range() // NOTE: currently ignoring_counter calling std::equal_range() // is not used anywhere in the code, still it's safer this way if (! geometry::has_nan_coordinate(front_pt)) { m_endpoints.push_back(front_pt); } if (! geometry::has_nan_coordinate(back_pt)) { m_endpoints.push_back(back_pt); } } } } m_has_boundary = false; if (! m_endpoints.empty() ) { std::sort(m_endpoints.begin(), m_endpoints.end(), less_type()); m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end()); } m_is_initialized = true; } template <typename It, typename Point> static inline std::size_t count_equal(It first, It last, Point const& point) { std::pair<It, It> rng = std::equal_range(first, last, point, less_type()); return (std::size_t)std::distance(rng.first, rng.second); } template <typename It> static inline bool find_odd_count(It first, It last) { interrupting_visitor visitor; for_each_boundary_point(first, last, visitor); return visitor.found; } struct interrupting_visitor { bool found; interrupting_visitor() : found(false) {} template <typename Point> bool apply(Point const&) { found = true; return false; } }; template <typename It, typename Visitor> static void for_each_boundary_point(It first, It last, Visitor& visitor) { if ( first == last ) return; std::size_t count = 1; It prev = first; ++first; for ( ; first != last ; ++first, ++prev ) { // the end of the equal points subrange if ( ! equals::equals_point_point(*first, *prev, EqPPStrategy()) ) { // odd count -> boundary if ( count % 2 != 0 ) { if (! visitor.apply(*prev)) { return; } } count = 1; } else { ++count; } } // odd count -> boundary if ( count % 2 != 0 ) { visitor.apply(*prev); } } private: MultiLinestring const& m_mls; mutable bool m_is_initialized; mutable bool m_has_interior; mutable bool m_has_boundary; typedef typename geometry::point_type<MultiLinestring>::type point_type; mutable std::vector<point_type> m_endpoints; }; struct topology_check_areal { static const char interior = '2'; static const char boundary = '1'; static bool has_interior() { return true; } static bool has_boundary() { return true; } }; template <typename Ring, typename EqPPStrategy> struct topology_check<Ring, EqPPStrategy, ring_tag> : topology_check_areal { topology_check(Ring const&) {} }; template <typename Polygon, typename EqPPStrategy> struct topology_check<Polygon, EqPPStrategy, polygon_tag> : topology_check_areal { topology_check(Polygon const&) {} }; template <typename MultiPolygon, typename EqPPStrategy> struct topology_check<MultiPolygon, EqPPStrategy, multi_polygon_tag> : topology_check_areal { topology_check(MultiPolygon const&) {} template <typename Point> static bool check_boundary_point(Point const& ) { return true; } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP detail/relate/point_point.hpp 0000644 00000022346 15125631656 0012356 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2017, 2018. // Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP #include <algorithm> #include <vector> #include <boost/range/empty.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/result.hpp> #include <boost/geometry/policies/compare.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template <typename Point1, typename Point2> struct point_point { static const bool interruption_enabled = false; template <typename Result, typename Strategy> static inline void apply(Point1 const& point1, Point2 const& point2, Result & result, Strategy const& strategy) { bool equal = detail::equals::equals_point_point(point1, point2, strategy); if ( equal ) { relate::set<interior, interior, '0'>(result); } else { relate::set<interior, exterior, '0'>(result); relate::set<exterior, interior, '0'>(result); } relate::set<exterior, exterior, result_dimension<Point1>::value>(result); } }; template <typename Point, typename MultiPoint, typename EqPPStrategy> std::pair<bool, bool> point_multipoint_check(Point const& point, MultiPoint const& multi_point, EqPPStrategy const& strategy) { bool found_inside = false; bool found_outside = false; // point_in_geometry could be used here but why iterate over MultiPoint twice? // we must search for a point in the exterior because all points in MultiPoint can be equal typedef typename boost::range_iterator<MultiPoint const>::type iterator; iterator it = boost::begin(multi_point); iterator last = boost::end(multi_point); for ( ; it != last ; ++it ) { bool ii = detail::equals::equals_point_point(point, *it, strategy); if ( ii ) found_inside = true; else found_outside = true; if ( found_inside && found_outside ) break; } return std::make_pair(found_inside, found_outside); } template <typename Point, typename MultiPoint, bool Transpose = false> struct point_multipoint { static const bool interruption_enabled = false; template <typename Result, typename Strategy> static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result, Strategy const& strategy) { if ( boost::empty(multi_point) ) { // TODO: throw on empty input? relate::set<interior, exterior, '0', Transpose>(result); return; } std::pair<bool, bool> rel = point_multipoint_check(point, multi_point, strategy); if ( rel.first ) // some point of MP is equal to P { relate::set<interior, interior, '0', Transpose>(result); if ( rel.second ) // a point of MP was found outside P { relate::set<exterior, interior, '0', Transpose>(result); } } else { relate::set<interior, exterior, '0', Transpose>(result); relate::set<exterior, interior, '0', Transpose>(result); } relate::set<exterior, exterior, result_dimension<Point>::value, Transpose>(result); } }; template <typename MultiPoint, typename Point> struct multipoint_point { static const bool interruption_enabled = false; template <typename Result, typename Strategy> static inline void apply(MultiPoint const& multi_point, Point const& point, Result & result, Strategy const& strategy) { point_multipoint<Point, MultiPoint, true>::apply(point, multi_point, result, strategy); } }; template <typename MultiPoint1, typename MultiPoint2> struct multipoint_multipoint { static const bool interruption_enabled = true; template <typename Result, typename Strategy> static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result, Strategy const& /*strategy*/) { typedef typename Strategy::cs_tag cs_tag; { // TODO: throw on empty input? bool empty1 = boost::empty(multi_point1); bool empty2 = boost::empty(multi_point2); if ( empty1 && empty2 ) { return; } else if ( empty1 ) { relate::set<exterior, interior, '0'>(result); return; } else if ( empty2 ) { relate::set<interior, exterior, '0'>(result); return; } } // The geometry containing smaller number of points will be analysed first if ( boost::size(multi_point1) < boost::size(multi_point2) ) { search_both<false, cs_tag>(multi_point1, multi_point2, result); } else { search_both<true, cs_tag>(multi_point2, multi_point1, result); } relate::set<exterior, exterior, result_dimension<MultiPoint1>::value>(result); } template <bool Transpose, typename CSTag, typename MPt1, typename MPt2, typename Result> static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt, Result & result) { if ( relate::may_update<interior, interior, '0'>(result) || relate::may_update<interior, exterior, '0'>(result) || relate::may_update<exterior, interior, '0'>(result) ) { // NlogN + MlogN bool is_disjoint = search<Transpose, CSTag>(first_sorted_mpt, first_iterated_mpt, result); if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) ) return; } if ( relate::may_update<interior, interior, '0'>(result) || relate::may_update<interior, exterior, '0'>(result) || relate::may_update<exterior, interior, '0'>(result) ) { // MlogM + NlogM search<! Transpose, CSTag>(first_iterated_mpt, first_sorted_mpt, result); } } template <bool Transpose, typename CSTag, typename SortedMultiPoint, typename IteratedMultiPoint, typename Result> static inline bool search(SortedMultiPoint const& sorted_mpt, IteratedMultiPoint const& iterated_mpt, Result & result) { // sort points from the 1 MPt typedef typename geometry::point_type<SortedMultiPoint>::type point_type; typedef geometry::less<void, -1, CSTag> less_type; std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt)); less_type const less = less_type(); std::sort(points.begin(), points.end(), less); bool found_inside = false; bool found_outside = false; // for each point in the second MPt typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator; for ( iterator it = boost::begin(iterated_mpt) ; it != boost::end(iterated_mpt) ; ++it ) { bool ii = std::binary_search(points.begin(), points.end(), *it, less); if ( ii ) found_inside = true; else found_outside = true; if ( found_inside && found_outside ) break; } if ( found_inside ) // some point of MP2 is equal to some of MP1 { // TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed // so if e.g. only I/I must be analysed we musn't check the other MPt relate::set<interior, interior, '0', Transpose>(result); if ( found_outside ) // some point of MP2 was found outside of MP1 { relate::set<exterior, interior, '0', Transpose>(result); } } else { relate::set<interior, exterior, '0', Transpose>(result); relate::set<exterior, interior, '0', Transpose>(result); } // if no point is intersecting the other MPt then we musn't analyse the reversed case return ! found_inside; } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_POINT_POINT_HPP detail/relate/linear_linear.hpp 0000644 00000105116 15125631656 0012615 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018, 2019. // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP #include <algorithm> #include <boost/core/ignore_unused.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/detail/single_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/point_geometry.hpp> #include <boost/geometry/algorithms/detail/relate/result.hpp> #include <boost/geometry/algorithms/detail/relate/turns.hpp> #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp> #include <boost/geometry/algorithms/detail/relate/follow_helpers.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template <typename Result, typename BoundaryChecker, bool TransposeResult> class disjoint_linestring_pred { typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type; public: disjoint_linestring_pred(Result & res, BoundaryChecker const& boundary_checker) : m_result(res) , m_boundary_checker(boundary_checker) , m_flags(0) { if ( ! may_update<interior, exterior, '1', TransposeResult>(m_result) ) { m_flags |= 1; } if ( ! may_update<boundary, exterior, '0', TransposeResult>(m_result) ) { m_flags |= 2; } } template <typename Linestring> bool operator()(Linestring const& linestring) { if ( m_flags == 3 ) { return false; } std::size_t const count = boost::size(linestring); // invalid input if ( count < 2 ) { // ignore // TODO: throw an exception? return true; } // point-like linestring if ( count == 2 && equals::equals_point_point(range::front(linestring), range::back(linestring), equals_strategy_type()) ) { update<interior, exterior, '0', TransposeResult>(m_result); } else { update<interior, exterior, '1', TransposeResult>(m_result); m_flags |= 1; // check if there is a boundary if ( m_flags < 2 && ( m_boundary_checker.template is_endpoint_boundary<boundary_front>(range::front(linestring)) || m_boundary_checker.template is_endpoint_boundary<boundary_back>(range::back(linestring)) ) ) { update<boundary, exterior, '0', TransposeResult>(m_result); m_flags |= 2; } } return m_flags != 3 && ! m_result.interrupt; } private: Result & m_result; BoundaryChecker const& m_boundary_checker; unsigned m_flags; }; template <typename Geometry1, typename Geometry2> struct linear_linear { static const bool interruption_enabled = true; typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; template <typename Result, typename IntersectionStrategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result, IntersectionStrategy const& intersection_strategy) { typedef typename IntersectionStrategy::cs_tag cs_tag; // The result should be FFFFFFFFF relate::set<exterior, exterior, result_dimension<Geometry1>::value>(result);// FFFFFFFFd, d in [1,9] or T if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; // get and analyse turns typedef typename turns::get_turns < Geometry1, Geometry2 >::template turn_info_type<IntersectionStrategy>::type turn_type; std::vector<turn_type> turns; interrupt_policy_linear_linear<Result> interrupt_policy(result); turns::get_turns < Geometry1, Geometry2, detail::get_turns::get_turn_info_type<Geometry1, Geometry2, turns::assign_policy<true> > >::apply(turns, geometry1, geometry2, interrupt_policy, intersection_strategy); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; typedef boundary_checker < Geometry1, typename IntersectionStrategy::point_in_point_strategy_type > boundary_checker1_type; boundary_checker1_type boundary_checker1(geometry1); disjoint_linestring_pred<Result, boundary_checker1_type, false> pred1(result, boundary_checker1); for_each_disjoint_geometry_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; typedef boundary_checker < Geometry2, typename IntersectionStrategy::point_in_point_strategy_type > boundary_checker2_type; boundary_checker2_type boundary_checker2(geometry2); disjoint_linestring_pred<Result, boundary_checker2_type, true> pred2(result, boundary_checker2); for_each_disjoint_geometry_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2); if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; if ( turns.empty() ) return; // TODO: turns must be sorted and followed only if it's possible to go out and in on the same point // for linear geometries union operation must be detected which I guess would be quite often if ( may_update<interior, interior, '1'>(result) || may_update<interior, boundary, '0'>(result) || may_update<interior, exterior, '1'>(result) || may_update<boundary, interior, '0'>(result) || may_update<boundary, boundary, '0'>(result) || may_update<boundary, exterior, '0'>(result) ) { typedef turns::less<0, turns::less_op_linear_linear<0>, cs_tag> less; std::sort(turns.begin(), turns.end(), less()); turns_analyser<turn_type, 0> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end(), geometry1, geometry2, boundary_checker1, boundary_checker2); } if ( BOOST_GEOMETRY_CONDITION( result.interrupt ) ) return; if ( may_update<interior, interior, '1', true>(result) || may_update<interior, boundary, '0', true>(result) || may_update<interior, exterior, '1', true>(result) || may_update<boundary, interior, '0', true>(result) || may_update<boundary, boundary, '0', true>(result) || may_update<boundary, exterior, '0', true>(result) ) { typedef turns::less<1, turns::less_op_linear_linear<1>, cs_tag> less; std::sort(turns.begin(), turns.end(), less()); turns_analyser<turn_type, 1> analyser; analyse_each_turn(result, analyser, turns.begin(), turns.end(), geometry2, geometry1, boundary_checker2, boundary_checker1); } } template <typename Result> class interrupt_policy_linear_linear { public: static bool const enabled = true; explicit interrupt_policy_linear_linear(Result & result) : m_result(result) {} // TODO: since we update result for some operations here, we may not do it in the analyser! template <typename Range> inline bool apply(Range const& turns) { typedef typename boost::range_iterator<Range const>::type iterator; for (iterator it = boost::begin(turns) ; it != boost::end(turns) ; ++it) { if ( it->operations[0].operation == overlay::operation_intersection || it->operations[1].operation == overlay::operation_intersection ) { update<interior, interior, '1'>(m_result); } else if ( ( it->operations[0].operation == overlay::operation_union || it->operations[0].operation == overlay::operation_blocked || it->operations[1].operation == overlay::operation_union || it->operations[1].operation == overlay::operation_blocked ) && it->operations[0].position == overlay::position_middle && it->operations[1].position == overlay::position_middle ) { // TODO: here we could also check the boundaries and set IB,BI,BB at this point update<interior, interior, '0'>(m_result); } } return m_result.interrupt; } private: Result & m_result; }; // This analyser should be used like Input or SinglePass Iterator template <typename TurnInfo, std::size_t OpId> class turns_analyser { typedef typename TurnInfo::point_type turn_point_type; static const std::size_t op_id = OpId; static const std::size_t other_op_id = (OpId + 1) % 2; static const bool transpose_result = OpId != 0; public: turns_analyser() : m_previous_turn_ptr(NULL) , m_previous_operation(overlay::operation_none) , m_degenerated_turn_ptr(NULL) , m_collinear_spike_exit(false) {} template <typename Result, typename TurnIt, typename Geometry, typename OtherGeometry, typename BoundaryChecker, typename OtherBoundaryChecker> void apply(Result & res, TurnIt it, Geometry const& geometry, OtherGeometry const& other_geometry, BoundaryChecker const& boundary_checker, OtherBoundaryChecker const& other_boundary_checker) { typedef typename BoundaryChecker::equals_strategy_type equals_strategy_type; overlay::operation_type const op = it->operations[op_id].operation; segment_identifier const& seg_id = it->operations[op_id].seg_id; segment_identifier const& other_id = it->operations[other_op_id].seg_id; bool const first_in_range = m_seg_watcher.update(seg_id); if ( op != overlay::operation_union && op != overlay::operation_intersection && op != overlay::operation_blocked ) { // degenerated turn if ( op == overlay::operation_continue && it->method == overlay::method_none && m_exit_watcher.is_outside(*it) /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none || ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it) )*/ ) { // TODO: rewrite the above condition // WARNING! For spikes the above condition may be TRUE // When degenerated turns are be marked in a different way than c,c/c // different condition will be checked handle_degenerated(res, *it, geometry, other_geometry, boundary_checker, other_boundary_checker, first_in_range); // TODO: not elegant solution! should be rewritten. if ( it->operations[op_id].position == overlay::position_back ) { m_previous_operation = overlay::operation_blocked; m_exit_watcher.reset_detected_exit(); } } return; } // reset m_degenerated_turn_ptr = NULL; // handle possible exit bool fake_enter_detected = false; if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) { // real exit point - may be multiple // we know that we entered and now we exit if ( ! turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it, equals_strategy_type()) ) { m_exit_watcher.reset_detected_exit(); // not the last IP update<interior, exterior, '1', transpose_result>(res); } // fake exit point, reset state else if ( op == overlay::operation_intersection ) { m_exit_watcher.reset_detected_exit(); fake_enter_detected = true; } } else if ( m_exit_watcher.get_exit_operation() == overlay::operation_blocked ) { // ignore multiple BLOCKs if ( op == overlay::operation_blocked ) return; if ( op == overlay::operation_intersection && turn_on_the_same_ip<op_id>(m_exit_watcher.get_exit_turn(), *it, equals_strategy_type()) ) { fake_enter_detected = true; } m_exit_watcher.reset_detected_exit(); } // i/i, i/x, i/u if ( op == overlay::operation_intersection ) { bool const was_outside = m_exit_watcher.is_outside(); m_exit_watcher.enter(*it); // interiors overlaps update<interior, interior, '1', transpose_result>(res); bool const this_b = it->operations[op_id].position == overlay::position_front // ignore spikes! && is_ip_on_boundary<boundary_front>(it->point, it->operations[op_id], boundary_checker, seg_id); // going inside on boundary point // may be front only if ( this_b ) { // may be front and back bool const other_b = is_ip_on_boundary<boundary_any>(it->point, it->operations[other_op_id], other_boundary_checker, other_id); // it's also the boundary of the other geometry if ( other_b ) { update<boundary, boundary, '0', transpose_result>(res); } else { update<boundary, interior, '0', transpose_result>(res); } } // going inside on non-boundary point else { // if we didn't enter in the past, we were outside if ( was_outside && ! fake_enter_detected && it->operations[op_id].position != overlay::position_front && ! m_collinear_spike_exit ) { update<interior, exterior, '1', transpose_result>(res); // if it's the first IP then the first point is outside if ( first_in_range ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); } } } } m_collinear_spike_exit = false; } // u/i, u/u, u/x, x/i, x/u, x/x else if ( op == overlay::operation_union || op == overlay::operation_blocked ) { // TODO: is exit watcher still needed? // couldn't is_collinear and some going inside counter be used instead? bool const is_collinear = it->operations[op_id].is_collinear; bool const was_outside = m_exit_watcher.is_outside() && m_exit_watcher.get_exit_operation() == overlay::operation_none; // TODO: move the above condition into the exit_watcher? // to exit we must be currently inside and the current segment must be collinear if ( !was_outside && is_collinear ) { m_exit_watcher.exit(*it, false); // if the position is not set to back it must be a spike if ( it->operations[op_id].position != overlay::position_back ) { m_collinear_spike_exit = true; } } bool const op_blocked = op == overlay::operation_blocked; // we're inside and going out from inside // possibly going out right now if ( ! was_outside && is_collinear ) { if ( op_blocked && it->operations[op_id].position == overlay::position_back ) // ignore spikes! { // check if this is indeed the boundary point // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same if ( is_endpoint_on_boundary<boundary_back>(it->point, boundary_checker) ) { // may be front and back bool const other_b = is_ip_on_boundary<boundary_any>(it->point, it->operations[other_op_id], other_boundary_checker, other_id); // it's also the boundary of the other geometry if ( other_b ) { update<boundary, boundary, '0', transpose_result>(res); } else { update<boundary, interior, '0', transpose_result>(res); } } } } // we're outside or intersects some segment from the outside else { // if we are truly outside if ( was_outside && it->operations[op_id].position != overlay::position_front && ! m_collinear_spike_exit /*&& !is_collinear*/ ) { update<interior, exterior, '1', transpose_result>(res); } // boundaries don't overlap - just an optimization if ( it->method == overlay::method_crosses ) { // the L1 is going from one side of the L2 to the other through the point update<interior, interior, '0', transpose_result>(res); // it's the first point in range if ( first_in_range ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); } } } // method other than crosses, check more conditions else { bool const this_b = is_ip_on_boundary<boundary_any>(it->point, it->operations[op_id], boundary_checker, seg_id); bool const other_b = is_ip_on_boundary<boundary_any>(it->point, it->operations[other_op_id], other_boundary_checker, other_id); // if current IP is on boundary of the geometry if ( this_b ) { // it's also the boundary of the other geometry if ( other_b ) { update<boundary, boundary, '0', transpose_result>(res); } else { update<boundary, interior, '0', transpose_result>(res); } } // if current IP is not on boundary of the geometry else { // it's also the boundary of the other geometry if ( other_b ) { update<interior, boundary, '0', transpose_result>(res); } else { update<interior, interior, '0', transpose_result>(res); } } // first IP on the last segment point - this means that the first point is outside if ( first_in_range && ( !this_b || op_blocked ) && was_outside && it->operations[op_id].position != overlay::position_front && ! m_collinear_spike_exit /*&& !is_collinear*/ ) { bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); } } } } } // store ref to previously analysed (valid) turn m_previous_turn_ptr = boost::addressof(*it); // and previously analysed (valid) operation m_previous_operation = op; } // Called for last template <typename Result, typename TurnIt, typename Geometry, typename OtherGeometry, typename BoundaryChecker, typename OtherBoundaryChecker> void apply(Result & res, TurnIt first, TurnIt last, Geometry const& geometry, OtherGeometry const& /*other_geometry*/, BoundaryChecker const& boundary_checker, OtherBoundaryChecker const& /*other_boundary_checker*/) { boost::ignore_unused(first, last); //BOOST_GEOMETRY_ASSERT( first != last ); // here, the possible exit is the real one // we know that we entered and now we exit if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT ||*/ m_previous_operation == overlay::operation_union || m_degenerated_turn_ptr ) { update<interior, exterior, '1', transpose_result>(res); BOOST_GEOMETRY_ASSERT(first != last); const TurnInfo * turn_ptr = NULL; if ( m_degenerated_turn_ptr ) turn_ptr = m_degenerated_turn_ptr; else if ( m_previous_turn_ptr ) turn_ptr = m_previous_turn_ptr; if ( turn_ptr ) { segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id; //BOOST_GEOMETRY_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id))); bool const prev_back_b = is_endpoint_on_boundary<boundary_back>( range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point if ( prev_back_b ) { update<boundary, exterior, '0', transpose_result>(res); } } } // Just in case, // reset exit watcher before the analysis of the next Linestring // note that if there are some enters stored there may be some error above m_exit_watcher.reset(); m_previous_turn_ptr = NULL; m_previous_operation = overlay::operation_none; m_degenerated_turn_ptr = NULL; // actually if this is set to true here there is some error // in get_turns_ll or relate_ll, an assert could be checked here m_collinear_spike_exit = false; } template <typename Result, typename Turn, typename Geometry, typename OtherGeometry, typename BoundaryChecker, typename OtherBoundaryChecker> void handle_degenerated(Result & res, Turn const& turn, Geometry const& geometry, OtherGeometry const& other_geometry, BoundaryChecker const& boundary_checker, OtherBoundaryChecker const& /*other_boundary_checker*/, bool first_in_range) { typedef typename BoundaryChecker::equals_strategy_type equals_strategy1_type; typedef typename OtherBoundaryChecker::equals_strategy_type equals_strategy2_type; typename detail::single_geometry_return_type<Geometry const>::type ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id); typename detail::single_geometry_return_type<OtherGeometry const>::type ls2_ref = detail::single_geometry(other_geometry, turn.operations[other_op_id].seg_id); // only one of those should be true: if ( turn.operations[op_id].position == overlay::position_front ) { // valid, point-sized if ( boost::size(ls2_ref) == 2 ) { bool const front_b = is_endpoint_on_boundary<boundary_front>(turn.point, boundary_checker); if ( front_b ) { update<boundary, interior, '0', transpose_result>(res); } else { update<interior, interior, '0', transpose_result>(res); } // operation 'c' should be last for the same IP so we know that the next point won't be the same update<interior, exterior, '1', transpose_result>(res); m_degenerated_turn_ptr = boost::addressof(turn); } } else if ( turn.operations[op_id].position == overlay::position_back ) { // valid, point-sized if ( boost::size(ls2_ref) == 2 ) { update<interior, exterior, '1', transpose_result>(res); bool const back_b = is_endpoint_on_boundary<boundary_back>(turn.point, boundary_checker); if ( back_b ) { update<boundary, interior, '0', transpose_result>(res); } else { update<interior, interior, '0', transpose_result>(res); } if ( first_in_range ) { //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref)); bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(ls1_ref), boundary_checker); if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); } } } } else if ( turn.operations[op_id].position == overlay::position_middle && turn.operations[other_op_id].position == overlay::position_middle ) { update<interior, interior, '0', transpose_result>(res); // here we don't know which one is degenerated bool const is_point1 = boost::size(ls1_ref) == 2 && equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref), equals_strategy1_type()); bool const is_point2 = boost::size(ls2_ref) == 2 && equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref), equals_strategy2_type()); // if the second one is degenerated if ( !is_point1 && is_point2 ) { update<interior, exterior, '1', transpose_result>(res); if ( first_in_range ) { //BOOST_GEOMETRY_ASSERT(!boost::empty(ls1_ref)); bool const front_b = is_endpoint_on_boundary<boundary_front>( range::front(ls1_ref), boundary_checker); if ( front_b ) { update<boundary, exterior, '0', transpose_result>(res); } } m_degenerated_turn_ptr = boost::addressof(turn); } } // NOTE: other.position == front and other.position == back // will be handled later, for the other geometry } private: exit_watcher<TurnInfo, OpId> m_exit_watcher; segment_watcher<same_single> m_seg_watcher; const TurnInfo * m_previous_turn_ptr; overlay::operation_type m_previous_operation; const TurnInfo * m_degenerated_turn_ptr; bool m_collinear_spike_exit; }; template <typename Result, typename TurnIt, typename Analyser, typename Geometry, typename OtherGeometry, typename BoundaryChecker, typename OtherBoundaryChecker> static inline void analyse_each_turn(Result & res, Analyser & analyser, TurnIt first, TurnIt last, Geometry const& geometry, OtherGeometry const& other_geometry, BoundaryChecker const& boundary_checker, OtherBoundaryChecker const& other_boundary_checker) { if ( first == last ) return; for ( TurnIt it = first ; it != last ; ++it ) { analyser.apply(res, it, geometry, other_geometry, boundary_checker, other_boundary_checker); if ( BOOST_GEOMETRY_CONDITION( res.interrupt ) ) return; } analyser.apply(res, first, last, geometry, other_geometry, boundary_checker, other_boundary_checker); } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP detail/get_max_size.hpp 0000644 00000004006 15125631656 0011207 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2014 Bruno Lalande, Paris, France. // Copyright (c) 2014 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2018. // Modifications copyright (c) 2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP #include <cstddef> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename Box, std::size_t Dimension> struct get_max_size_box { static inline typename coordinate_type<Box>::type apply(Box const& box) { typename coordinate_type<Box>::type s = geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box)); return (std::max)(s, get_max_size_box<Box, Dimension - 1>::apply(box)); } }; template <typename Box> struct get_max_size_box<Box, 0> { static inline typename coordinate_type<Box>::type apply(Box const& box) { return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box)); } }; // This might be implemented later on for other geometries too. // Not dispatched yet. template <typename Box> inline typename coordinate_type<Box>::type get_max_size(Box const& box) { return get_max_size_box<Box, dimension<Box>::value - 1>::apply(box); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP detail/is_valid/has_duplicates.hpp 0000644 00000004463 15125631656 0013322 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_HAS_DUPLICATES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template <typename Range, closure_selector Closure, typename CSTag> struct has_duplicates { template <typename VisitPolicy> static inline bool apply(Range const& range, VisitPolicy& visitor) { boost::ignore_unused(visitor); typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename boost::range_const_iterator < view_type const >::type const_iterator; view_type view(range); if ( boost::size(view) < 2 ) { return ! visitor.template apply<no_failure>(); } geometry::equal_to < typename boost::range_value<Range>::type, -1, CSTag > equal; const_iterator it = boost::const_begin(view); const_iterator next = it; ++next; for (; next != boost::const_end(view); ++it, ++next) { if ( equal(*it, *next) ) { return ! visitor.template apply<failure_duplicate_points>(*it); } } return ! visitor.template apply<no_failure>(); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_DUPLICATES_HPP detail/is_valid/linear.hpp 0000644 00000014031 15125631656 0011574 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP #include <cstddef> #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template <typename Linestring> struct is_valid_linestring { template <typename VisitPolicy, typename Strategy> static inline bool apply(Linestring const& linestring, VisitPolicy& visitor, Strategy const& strategy) { // TODO: Consider checking coordinates based on coordinate system // Right now they are only checked for infinity in all systems. if (has_invalid_coordinate<Linestring>::apply(linestring, visitor)) { return false; } if (boost::size(linestring) < 2) { return visitor.template apply<failure_few_points>(); } std::size_t num_distinct = detail::num_distinct_consecutive_points < Linestring, 3u, true, not_equal_to < typename point_type<Linestring>::type, typename Strategy::equals_point_point_strategy_type > >::apply(linestring); if (num_distinct < 2u) { return visitor.template apply<failure_wrong_topological_dimension>(); } if (num_distinct == 2u) { return visitor.template apply<no_failure>(); } // TODO: This algorithm iterates over the linestring until a spike is // found and only then the decision about the validity is made. This // is done regardless of VisitPolicy. // An obvious improvement is to avoid calling the algorithm at all if // spikes are allowed which is the default. return ! has_spikes < Linestring, closed >::apply(linestring, visitor, strategy.get_side_strategy()); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A linestring is a curve. // A curve is 1-dimensional so it has to have at least two distinct // points. // A curve is simple if it does not pass through the same point twice, // with the possible exception of its two endpoints // // There is an option here as to whether spikes are allowed for linestrings; // here we pass this as an additional template parameter: allow_spikes // If allow_spikes is set to true, spikes are allowed, false otherwise. // By default, spikes are disallowed // // Reference: OGC 06-103r4 (6.1.6.1) template <typename Linestring, bool AllowEmptyMultiGeometries> struct is_valid < Linestring, linestring_tag, AllowEmptyMultiGeometries > : detail::is_valid::is_valid_linestring<Linestring> {}; // A MultiLinestring is a MultiCurve // A MultiCurve is simple if all of its elements are simple and the // only intersections between any two elements occur at Points that // are on the boundaries of both elements. // // Reference: OGC 06-103r4 (6.1.8.1; Fig. 9) template <typename MultiLinestring, bool AllowEmptyMultiGeometries> class is_valid < MultiLinestring, multi_linestring_tag, AllowEmptyMultiGeometries > { private: template <typename VisitPolicy, typename Strategy> struct per_linestring { per_linestring(VisitPolicy& policy, Strategy const& strategy) : m_policy(policy) , m_strategy(strategy) {} template <typename Linestring> inline bool apply(Linestring const& linestring) const { return detail::is_valid::is_valid_linestring < Linestring >::apply(linestring, m_policy, m_strategy); } VisitPolicy& m_policy; Strategy const& m_strategy; }; public: template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiLinestring const& multilinestring, VisitPolicy& visitor, Strategy const& strategy) { if (BOOST_GEOMETRY_CONDITION( AllowEmptyMultiGeometries && boost::empty(multilinestring))) { return visitor.template apply<no_failure>(); } typedef per_linestring<VisitPolicy, Strategy> per_ls; return detail::check_iterator_range < per_ls, false // do not check for empty multilinestring (done above) >::apply(boost::begin(multilinestring), boost::end(multilinestring), per_ls(visitor, strategy)); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINEAR_HPP detail/is_valid/complement_graph.hpp 0000644 00000015337 15125631656 0013660 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2018, 2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP #include <cstddef> #include <set> #include <stack> #include <utility> #include <vector> #include <boost/core/addressof.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/policies/compare.hpp> namespace boost { namespace geometry { namespace detail { namespace is_valid { template <typename TurnPoint, typename CSTag> class complement_graph_vertex { public: complement_graph_vertex(std::size_t id) : m_id(id) , m_turn_point(NULL) {} complement_graph_vertex(TurnPoint const* turn_point, std::size_t expected_id) : m_id(expected_id) , m_turn_point(turn_point) {} inline std::size_t id() const { return m_id; } inline bool operator<(complement_graph_vertex const& other) const { if ( m_turn_point != NULL && other.m_turn_point != NULL ) { return geometry::less < TurnPoint, -1, CSTag >()(*m_turn_point, *other.m_turn_point); } if ( m_turn_point == NULL && other.m_turn_point == NULL ) { return m_id < other.m_id; } return m_turn_point == NULL; } private: // the value of m_turn_point determines the type of the vertex // non-NULL: vertex corresponds to an IP // NULL : vertex corresponds to a hole or outer space, and the id // is the ring id of the corresponding ring of the polygon std::size_t m_id; TurnPoint const* m_turn_point; }; template <typename TurnPoint, typename CSTag> class complement_graph { private: typedef complement_graph_vertex<TurnPoint, CSTag> vertex; typedef std::set<vertex> vertex_container; public: typedef typename vertex_container::const_iterator vertex_handle; private: struct vertex_handle_less { inline bool operator()(vertex_handle v1, vertex_handle v2) const { return v1->id() < v2->id(); } }; typedef std::set<vertex_handle, vertex_handle_less> neighbor_container; class has_cycles_dfs_data { public: has_cycles_dfs_data(std::size_t num_nodes) : m_visited(num_nodes, false) , m_parent_id(num_nodes, -1) {} inline signed_size_type parent_id(vertex_handle v) const { return m_parent_id[v->id()]; } inline void set_parent_id(vertex_handle v, signed_size_type id) { m_parent_id[v->id()] = id; } inline bool visited(vertex_handle v) const { return m_visited[v->id()]; } inline void set_visited(vertex_handle v, bool value) { m_visited[v->id()] = value; } private: std::vector<bool> m_visited; std::vector<signed_size_type> m_parent_id; }; inline bool has_cycles(vertex_handle start_vertex, has_cycles_dfs_data& data) const { std::stack<vertex_handle> stack; stack.push(start_vertex); while ( !stack.empty() ) { vertex_handle v = stack.top(); stack.pop(); data.set_visited(v, true); for (typename neighbor_container::const_iterator nit = m_neighbors[v->id()].begin(); nit != m_neighbors[v->id()].end(); ++nit) { if ( static_cast<signed_size_type>((*nit)->id()) != data.parent_id(v) ) { if ( data.visited(*nit) ) { return true; } else { data.set_parent_id(*nit, static_cast<signed_size_type>(v->id())); stack.push(*nit); } } } } return false; } public: // num_rings: total number of rings, including the exterior ring complement_graph(std::size_t num_rings) : m_num_rings(num_rings) , m_num_turns(0) , m_vertices() , m_neighbors(num_rings) {} // inserts a ring vertex in the graph and returns its handle // ring id's are zero-based (so the first interior ring has id 1) inline vertex_handle add_vertex(signed_size_type id) { return m_vertices.insert(vertex(static_cast<std::size_t>(id))).first; } // inserts an IP in the graph and returns its id inline vertex_handle add_vertex(TurnPoint const& turn_point) { std::pair<vertex_handle, bool> res = m_vertices.insert(vertex(boost::addressof(turn_point), m_num_rings + m_num_turns) ); if ( res.second ) { // a new element is inserted m_neighbors.push_back(neighbor_container()); ++m_num_turns; } return res.first; } inline void add_edge(vertex_handle v1, vertex_handle v2) { BOOST_GEOMETRY_ASSERT( v1 != m_vertices.end() ); BOOST_GEOMETRY_ASSERT( v2 != m_vertices.end() ); m_neighbors[v1->id()].insert(v2); m_neighbors[v2->id()].insert(v1); } inline bool has_cycles() const { // initialize all vertices as non-visited and with no parent set // this is done by the constructor of has_cycles_dfs_data has_cycles_dfs_data data(m_num_rings + m_num_turns); // for each non-visited vertex, start a DFS from that vertex for (vertex_handle it = m_vertices.begin(); it != m_vertices.end(); ++it) { if ( !data.visited(it) && has_cycles(it, data) ) { return true; } } return false; } #ifdef BOOST_GEOMETRY_TEST_DEBUG template <typename OStream, typename TP> friend inline void debug_print_complement_graph(OStream&, complement_graph<TP> const&); #endif // BOOST_GEOMETRY_TEST_DEBUG private: std::size_t m_num_rings, m_num_turns; vertex_container m_vertices; std::vector<neighbor_container> m_neighbors; }; }} // namespace detail::is_valid }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP detail/is_valid/debug_print_turns.hpp 0000644 00000004304 15125631656 0014061 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP #ifdef BOOST_GEOMETRY_TEST_DEBUG #include <iostream> #include <boost/geometry/io/dsv/write.hpp> #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> #endif namespace boost { namespace geometry { namespace detail { namespace is_valid { #ifdef BOOST_GEOMETRY_TEST_DEBUG template <typename Turn> inline void debug_print_turn(Turn const& turn) { std::cout << " [" << geometry::method_char(turn.method) << "," << geometry::operation_char(turn.operations[0].operation) << "/" << geometry::operation_char(turn.operations[1].operation) << " {" << turn.operations[0].seg_id.multi_index << ", " << turn.operations[1].seg_id.multi_index << "} {" << turn.operations[0].seg_id.ring_index << ", " << turn.operations[1].seg_id.ring_index << "} {" << turn.operations[0].seg_id.segment_index << ", " << turn.operations[1].seg_id.segment_index << "} " << geometry::dsv(turn.point) << "]"; } template <typename TurnIterator> inline void debug_print_turns(TurnIterator first, TurnIterator beyond) { std::cout << "turns:"; for (TurnIterator tit = first; tit != beyond; ++tit) { debug_print_turn(*tit); } std::cout << std::endl << std::endl; } #else template <typename Turn> inline void debug_print_turn(Turn const&) {} template <typename TurnIterator> inline void debug_print_turns(TurnIterator, TurnIterator) {} #endif // BOOST_GEOMETRY_TEST_DEBUG }} // namespace detail::is_valid }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_PRINT_TURNS_HPP detail/is_valid/implementation.hpp 0000644 00000001667 15125631656 0013362 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/is_valid/pointlike.hpp> #include <boost/geometry/algorithms/detail/is_valid/linear.hpp> #include <boost/geometry/algorithms/detail/is_valid/polygon.hpp> #include <boost/geometry/algorithms/detail/is_valid/multipolygon.hpp> #include <boost/geometry/algorithms/detail/is_valid/ring.hpp> #include <boost/geometry/algorithms/detail/is_valid/segment.hpp> #include <boost/geometry/algorithms/detail/is_valid/box.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IMPLEMENTATION_HPP detail/is_valid/debug_complement_graph.hpp 0000644 00000004263 15125631656 0015022 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2018, 2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_COMPLEMENT_GRAPH_HPP #ifdef BOOST_GEOMETRY_TEST_DEBUG #include <iostream> #endif #include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp> namespace boost { namespace geometry { namespace detail { namespace is_valid { #ifdef BOOST_GEOMETRY_TEST_DEBUG template <typename OutputStream, typename TurnPoint, typename CSTag> inline void debug_print_complement_graph(OutputStream& os, complement_graph<TurnPoint, CSTag> const& graph) { typedef typename complement_graph<TurnPoint>::vertex_handle vertex_handle; os << "num rings: " << graph.m_num_rings << std::endl; os << "vertex ids: {"; for (vertex_handle it = graph.m_vertices.begin(); it != graph.m_vertices.end(); ++it) { os << " " << it->id(); } os << " }" << std::endl; for (vertex_handle it = graph.m_vertices.begin(); it != graph.m_vertices.end(); ++it) { os << "neighbors of " << it->id() << ": {"; for (typename complement_graph < TurnPoint >::neighbor_container::const_iterator nit = graph.m_neighbors[it->id()].begin(); nit != graph.m_neighbors[it->id()].end(); ++nit) { os << " " << (*nit)->id(); } os << "}" << std::endl; } } #else template <typename OutputStream, typename TurnPoint, typename CSTag> inline void debug_print_complement_graph(OutputStream&, complement_graph<TurnPoint, CSTag> const&) { } #endif }} // namespace detail::is_valid }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_COMPLEMENT_GRAPH_HPP detail/is_valid/debug_validity_phase.hpp 0000644 00000003455 15125631656 0014505 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP #ifdef GEOMETRY_TEST_DEBUG #include <iostream> #endif #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { namespace detail { namespace is_valid { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct debug_validity_phase { static inline void apply(int) { } }; #ifdef BOOST_GEOMETRY_TEST_DEBUG template <typename Polygon> struct debug_validity_phase<Polygon, polygon_tag> { static inline void apply(int phase) { switch (phase) { case 1: std::cout << "checking exterior ring..." << std::endl; break; case 2: std::cout << "checking interior rings..." << std::endl; break; case 3: std::cout << "computing and analyzing turns..." << std::endl; break; case 4: std::cout << "checking if interior rings are inside " << "the exterior ring..." << std::endl; break; case 5: std::cout << "checking connectivity of interior..." << std::endl; break; } } }; #endif }} // namespace detail::is_valid }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_DEBUG_VALIDITY_PHASE_HPP detail/is_valid/is_acceptable_turn.hpp 0000644 00000010446 15125631656 0014156 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP #include <boost/range/value_type.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template < typename Geometry, order_selector Order = geometry::point_order<Geometry>::value, typename Tag = typename tag<Geometry>::type > struct acceptable_operation {}; template <typename Polygon> struct acceptable_operation<Polygon, counterclockwise, polygon_tag> { static const detail::overlay::operation_type value = detail::overlay::operation_union; }; template <typename Polygon> struct acceptable_operation<Polygon, clockwise, polygon_tag> { static const detail::overlay::operation_type value = detail::overlay::operation_intersection; }; template <typename MultiPolygon> struct acceptable_operation<MultiPolygon, counterclockwise, multi_polygon_tag> { static const detail::overlay::operation_type value = detail::overlay::operation_intersection; }; template <typename MultiPolygon> struct acceptable_operation<MultiPolygon, clockwise, multi_polygon_tag> { static const detail::overlay::operation_type value = detail::overlay::operation_union; }; template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct is_acceptable_turn {}; template <typename Ring> struct is_acceptable_turn<Ring, ring_tag> { template <typename Turn> static inline bool apply(Turn const&) { return false; } }; template <typename Polygon> class is_acceptable_turn<Polygon, polygon_tag> { protected: template <typename Turn, typename Method, typename Operation> static inline bool check_turn(Turn const& turn, Method method, Operation operation) { return turn.method == method && turn.operations[0].operation == operation && turn.operations[1].operation == operation; } public: template <typename Turn> static inline bool apply(Turn const& turn) { using namespace detail::overlay; if ( turn.operations[0].seg_id.ring_index == turn.operations[1].seg_id.ring_index ) { return false; } operation_type const op = acceptable_operation<Polygon>::value; return check_turn(turn, method_touch_interior, op) || check_turn(turn, method_touch, op) ; } }; template <typename MultiPolygon> class is_acceptable_turn<MultiPolygon, multi_polygon_tag> : is_acceptable_turn<typename boost::range_value<MultiPolygon>::type> { private: typedef typename boost::range_value<MultiPolygon>::type polygon; typedef is_acceptable_turn<polygon> base; public: template <typename Turn> static inline bool apply(Turn const& turn) { using namespace detail::overlay; if ( turn.operations[0].seg_id.multi_index == turn.operations[1].seg_id.multi_index ) { return base::apply(turn); } operation_type const op = acceptable_operation<MultiPolygon>::value; if ( base::check_turn(turn, method_touch_interior, op) || base::check_turn(turn, method_touch, op)) { return true; } // Turn is acceptable only in case of a touch(interior) and both lines // (polygons) do not cross return (turn.method == method_touch || turn.method == method_touch_interior) && turn.touch_only; } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_IS_ACCEPTABLE_TURN_HPP detail/is_valid/pointlike.hpp 0000644 00000005125 15125631656 0012324 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_POINTLIKE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP #include <boost/core/ignore_unused.hpp> #include <boost/range/empty.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A point is always simple template <typename Point> struct is_valid<Point, point_tag> { template <typename VisitPolicy, typename Strategy> static inline bool apply(Point const& point, VisitPolicy& visitor, Strategy const&) { boost::ignore_unused(visitor); return ! detail::is_valid::has_invalid_coordinate < Point >::apply(point, visitor); } }; // A MultiPoint is simple if no two Points in the MultiPoint are equal // (have identical coordinate values in X and Y) // // Reference: OGC 06-103r4 (6.1.5) template <typename MultiPoint, bool AllowEmptyMultiGeometries> struct is_valid<MultiPoint, multi_point_tag, AllowEmptyMultiGeometries> { template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiPoint const& multipoint, VisitPolicy& visitor, Strategy const&) { boost::ignore_unused(multipoint, visitor); if (BOOST_GEOMETRY_CONDITION( AllowEmptyMultiGeometries || !boost::empty(multipoint))) { // we allow empty multi-geometries, so an empty multipoint // is considered valid return ! detail::is_valid::has_invalid_coordinate < MultiPoint >::apply(multipoint, visitor); } else { // we do not allow an empty multipoint return visitor.template apply<failure_few_points>(); } } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP detail/is_valid/multipolygon.hpp 0000644 00000032416 15125631656 0013073 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_MULTIPOLYGON_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP #include <deque> #include <vector> #include <boost/core/ignore_unused.hpp> #include <boost/iterator/filter_iterator.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> #include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> #include <boost/geometry/algorithms/detail/is_valid/polygon.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> #include <boost/geometry/strategies/intersection.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template <typename MultiPolygon, bool AllowEmptyMultiGeometries> class is_valid_multipolygon : is_valid_polygon < typename boost::range_value<MultiPolygon>::type, true // check only the validity of rings > { private: typedef is_valid_polygon < typename boost::range_value<MultiPolygon>::type, true > base; template < typename PolygonIterator, typename TurnIterator, typename VisitPolicy, typename Strategy > static inline bool are_polygon_interiors_disjoint(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, TurnIterator turns_beyond, VisitPolicy& visitor, Strategy const& strategy) { boost::ignore_unused(visitor); // collect all polygons that have crossing turns std::set<signed_size_type> multi_indices; for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) { if (! tit->touch_only) { multi_indices.insert(tit->operations[0].seg_id.multi_index); multi_indices.insert(tit->operations[1].seg_id.multi_index); } } typedef geometry::model::box<typename point_type<MultiPolygon>::type> box_type; typedef typename base::template partition_item<PolygonIterator, box_type> item_type; // put polygon iterators without turns in a vector std::vector<item_type> polygon_iterators; signed_size_type multi_index = 0; for (PolygonIterator it = polygons_first; it != polygons_beyond; ++it, ++multi_index) { if (multi_indices.find(multi_index) == multi_indices.end()) { polygon_iterators.push_back(item_type(it)); } } // prepare strategies typedef typename Strategy::envelope_strategy_type envelope_strategy_type; envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); typedef typename Strategy::disjoint_box_box_strategy_type disjoint_box_box_strategy_type; disjoint_box_box_strategy_type const disjoint_strategy = strategy.get_disjoint_box_box_strategy(); // call partition to check if polygons are disjoint from each other typename base::template item_visitor_type<Strategy> item_visitor(strategy); geometry::partition < geometry::model::box<typename point_type<MultiPolygon>::type> >::apply(polygon_iterators, item_visitor, typename base::template expand_box < envelope_strategy_type >(envelope_strategy), typename base::template overlaps_box < envelope_strategy_type, disjoint_box_box_strategy_type >(envelope_strategy, disjoint_strategy)); if (item_visitor.items_overlap) { return visitor.template apply<failure_intersecting_interiors>(); } else { return visitor.template apply<no_failure>(); } } class has_multi_index { public: has_multi_index(signed_size_type multi_index) : m_multi_index(multi_index) {} template <typename Turn> inline bool operator()(Turn const& turn) const { return turn.operations[0].seg_id.multi_index == m_multi_index && turn.operations[1].seg_id.multi_index == m_multi_index; } private: signed_size_type const m_multi_index; }; template <typename Predicate> struct has_property_per_polygon { template < typename PolygonIterator, typename TurnIterator, typename VisitPolicy, typename Strategy > static inline bool apply(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, TurnIterator turns_beyond, VisitPolicy& visitor, Strategy const& strategy) { signed_size_type multi_index = 0; for (PolygonIterator it = polygons_first; it != polygons_beyond; ++it, ++multi_index) { has_multi_index index_predicate(multi_index); typedef boost::filter_iterator < has_multi_index, TurnIterator > filtered_turn_iterator; filtered_turn_iterator filtered_turns_first(index_predicate, turns_first, turns_beyond); filtered_turn_iterator filtered_turns_beyond(index_predicate, turns_beyond, turns_beyond); if (! Predicate::apply(*it, filtered_turns_first, filtered_turns_beyond, visitor, strategy)) { return false; } } return true; } }; template < typename PolygonIterator, typename TurnIterator, typename VisitPolicy, typename Strategy > static inline bool have_holes_inside(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, TurnIterator turns_beyond, VisitPolicy& visitor, Strategy const& strategy) { return has_property_per_polygon < typename base::has_holes_inside >::apply(polygons_first, polygons_beyond, turns_first, turns_beyond, visitor, strategy); } template < typename PolygonIterator, typename TurnIterator, typename VisitPolicy, typename Strategy > static inline bool have_connected_interior(PolygonIterator polygons_first, PolygonIterator polygons_beyond, TurnIterator turns_first, TurnIterator turns_beyond, VisitPolicy& visitor, Strategy const& strategy) { return has_property_per_polygon < typename base::has_connected_interior >::apply(polygons_first, polygons_beyond, turns_first, turns_beyond, visitor, strategy); } template <typename VisitPolicy, typename Strategy> struct per_polygon { per_polygon(VisitPolicy& policy, Strategy const& strategy) : m_policy(policy) , m_strategy(strategy) {} template <typename Polygon> inline bool apply(Polygon const& polygon) const { return base::apply(polygon, m_policy, m_strategy); } VisitPolicy& m_policy; Strategy const& m_strategy; }; public: template <typename VisitPolicy, typename Strategy> static inline bool apply(MultiPolygon const& multipolygon, VisitPolicy& visitor, Strategy const& strategy) { typedef debug_validity_phase<MultiPolygon> debug_phase; if (BOOST_GEOMETRY_CONDITION(AllowEmptyMultiGeometries) && boost::empty(multipolygon)) { return visitor.template apply<no_failure>(); } // check validity of all polygons ring debug_phase::apply(1); if (! detail::check_iterator_range < per_polygon<VisitPolicy, Strategy>, false // do not check for empty multipolygon (done above) >::apply(boost::begin(multipolygon), boost::end(multipolygon), per_polygon<VisitPolicy, Strategy>(visitor, strategy))) { return false; } // compute turns and check if all are acceptable debug_phase::apply(2); typedef has_valid_self_turns<MultiPolygon, typename Strategy::cs_tag> has_valid_turns; std::deque<typename has_valid_turns::turn_type> turns; bool has_invalid_turns = ! has_valid_turns::apply(multipolygon, turns, visitor, strategy); debug_print_turns(turns.begin(), turns.end()); if (has_invalid_turns) { return false; } // check if each polygon's interior rings are inside the // exterior and not one inside the other debug_phase::apply(3); if (! have_holes_inside(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), turns.end(), visitor, strategy)) { return false; } // check that each polygon's interior is connected debug_phase::apply(4); if (! have_connected_interior(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), turns.end(), visitor, strategy)) { return false; } // check if polygon interiors are disjoint debug_phase::apply(5); return are_polygon_interiors_disjoint(boost::begin(multipolygon), boost::end(multipolygon), turns.begin(), turns.end(), visitor, strategy); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Not clear what the definition is. // Right now we check that each element is simple (in fact valid), and // that the MultiPolygon is also valid. // // Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14) template <typename MultiPolygon, bool AllowEmptyMultiGeometries> struct is_valid < MultiPolygon, multi_polygon_tag, AllowEmptyMultiGeometries > : detail::is_valid::is_valid_multipolygon < MultiPolygon, AllowEmptyMultiGeometries > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTIPOLYGON_HPP detail/is_valid/box.hpp 0000644 00000005752 15125631656 0011124 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP #include <cstddef> #include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template <typename Box, std::size_t I> struct has_valid_corners { template <typename VisitPolicy> static inline bool apply(Box const& box, VisitPolicy& visitor) { if (math::equals(geometry::get<geometry::min_corner, I-1>(box), geometry::get<geometry::max_corner, I-1>(box))) { return visitor.template apply<failure_wrong_topological_dimension>(); } else if (geometry::get<geometry::min_corner, I-1>(box) > geometry::get<geometry::max_corner, I-1>(box)) { return visitor.template apply<failure_wrong_corner_order>(); } return has_valid_corners<Box, I-1>::apply(box, visitor); } }; template <typename Box> struct has_valid_corners<Box, 0> { template <typename VisitPolicy> static inline bool apply(Box const&, VisitPolicy& visitor) { boost::ignore_unused(visitor); return visitor.template apply<no_failure>(); } }; template <typename Box> struct is_valid_box { template <typename VisitPolicy, typename Strategy> static inline bool apply(Box const& box, VisitPolicy& visitor, Strategy const&) { return ! has_invalid_coordinate<Box>::apply(box, visitor) && has_valid_corners<Box, dimension<Box>::value>::apply(box, visitor); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A box is always simple // A box is a Polygon, and it satisfies the conditions for Polygon validity. // // The only thing we have to check is whether the max corner lies in // the upper-right quadrant as defined by the min corner // // Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) template <typename Box> struct is_valid<Box, box_tag> : detail::is_valid::is_valid_box<Box> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP detail/is_valid/polygon.hpp 0000644 00000045100 15125631656 0012012 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_POLYGON_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP #include <cstddef> #ifdef BOOST_GEOMETRY_TEST_DEBUG #include <iostream> #endif // BOOST_GEOMETRY_TEST_DEBUG #include <algorithm> #include <deque> #include <iterator> #include <set> #include <vector> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/util/sequence.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/iterators/point_iterator.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/is_valid/complement_graph.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> #include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> #include <boost/geometry/algorithms/detail/is_valid/ring.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_validity_phase.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_complement_graph.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> // TEMP #include <boost/geometry/strategies/envelope/cartesian.hpp> #include <boost/geometry/strategies/envelope/geographic.hpp> #include <boost/geometry/strategies/envelope/spherical.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template <typename Polygon, bool CheckRingValidityOnly = false> class is_valid_polygon { protected: template <typename VisitPolicy, typename Strategy> struct per_ring { per_ring(VisitPolicy& policy, Strategy const& strategy) : m_policy(policy) , m_strategy(strategy) {} template <typename Ring> inline bool apply(Ring const& ring) const { return detail::is_valid::is_valid_ring < Ring, false, true >::apply(ring, m_policy, m_strategy); } VisitPolicy& m_policy; Strategy const& m_strategy; }; template <typename InteriorRings, typename VisitPolicy, typename Strategy> static bool has_valid_interior_rings(InteriorRings const& interior_rings, VisitPolicy& visitor, Strategy const& strategy) { return detail::check_iterator_range < per_ring<VisitPolicy, Strategy>, true // allow for empty interior ring range >::apply(boost::begin(interior_rings), boost::end(interior_rings), per_ring<VisitPolicy, Strategy>(visitor, strategy)); } struct has_valid_rings { template <typename VisitPolicy, typename Strategy> static inline bool apply(Polygon const& polygon, VisitPolicy& visitor, Strategy const& strategy) { typedef debug_validity_phase<Polygon> debug_phase; typedef typename ring_type<Polygon>::type ring_type; // check validity of exterior ring debug_phase::apply(1); if (! detail::is_valid::is_valid_ring < ring_type, false // do not check self intersections >::apply(exterior_ring(polygon), visitor, strategy)) { return false; } // check validity of interior rings debug_phase::apply(2); return has_valid_interior_rings(geometry::interior_rings(polygon), visitor, strategy); } }; // Iterator value_type is a Ring or Polygon template <typename Iterator, typename Box> struct partition_item { explicit partition_item(Iterator it) : m_it(it) , m_is_initialized(false) {} Iterator get() const { return m_it; } template <typename EnvelopeStrategy> Box const& get_envelope(EnvelopeStrategy const& strategy) const { if (! m_is_initialized) { m_box = geometry::return_envelope<Box>(*m_it, strategy); m_is_initialized = true; } return m_box; } private: Iterator m_it; mutable Box m_box; mutable bool m_is_initialized; }; // structs for partition -- start template <typename EnvelopeStrategy> struct expand_box { explicit expand_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {} template <typename Box, typename Iterator> inline void apply(Box& total, partition_item<Iterator, Box> const& item) const { geometry::expand(total, item.get_envelope(m_strategy), // TEMP - envelope umbrella strategy also contains // expand strategies strategies::envelope::services::strategy_converter < EnvelopeStrategy >::get(m_strategy)); } EnvelopeStrategy const& m_strategy; }; template <typename EnvelopeStrategy, typename DisjointBoxBoxStrategy> struct overlaps_box { explicit overlaps_box(EnvelopeStrategy const& envelope_strategy, DisjointBoxBoxStrategy const& disjoint_strategy) : m_envelope_strategy(envelope_strategy) , m_disjoint_strategy(disjoint_strategy) {} template <typename Box, typename Iterator> inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const { return ! geometry::disjoint(item.get_envelope(m_envelope_strategy), box, m_disjoint_strategy); } EnvelopeStrategy const& m_envelope_strategy; DisjointBoxBoxStrategy const& m_disjoint_strategy; }; template <typename WithinStrategy> struct item_visitor_type { bool items_overlap; WithinStrategy const& m_strategy; explicit item_visitor_type(WithinStrategy const& strategy) : items_overlap(false) , m_strategy(strategy) {} template <typename Iterator, typename Box> inline bool apply(partition_item<Iterator, Box> const& item1, partition_item<Iterator, Box> const& item2) { typedef util::type_sequence < geometry::de9im::static_mask<'T'>, geometry::de9im::static_mask<'*', 'T'>, geometry::de9im::static_mask<'*', '*', '*', 'T'> > relate_mask_t; if ( ! items_overlap && geometry::relate(*item1.get(), *item2.get(), relate_mask_t(), m_strategy) ) { items_overlap = true; return false; // interrupt } return true; } }; // structs for partition -- end template < typename RingIterator, typename ExteriorRing, typename TurnIterator, typename VisitPolicy, typename Strategy > static inline bool are_holes_inside(RingIterator rings_first, RingIterator rings_beyond, ExteriorRing const& exterior_ring, TurnIterator turns_first, TurnIterator turns_beyond, VisitPolicy& visitor, Strategy const& strategy) { boost::ignore_unused(visitor); // collect the interior ring indices that have turns with the // exterior ring std::set<signed_size_type> ring_indices; for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) { if (tit->operations[0].seg_id.ring_index == -1) { BOOST_GEOMETRY_ASSERT(tit->operations[1].seg_id.ring_index != -1); ring_indices.insert(tit->operations[1].seg_id.ring_index); } else if (tit->operations[1].seg_id.ring_index == -1) { BOOST_GEOMETRY_ASSERT(tit->operations[0].seg_id.ring_index != -1); ring_indices.insert(tit->operations[0].seg_id.ring_index); } } // prepare strategy typedef typename std::iterator_traits<RingIterator>::value_type inter_ring_type; typename Strategy::template point_in_geometry_strategy < inter_ring_type, ExteriorRing >::type const in_exterior_strategy = strategy.template get_point_in_geometry_strategy<inter_ring_type, ExteriorRing>(); signed_size_type ring_index = 0; for (RingIterator it = rings_first; it != rings_beyond; ++it, ++ring_index) { // do not examine interior rings that have turns with the // exterior ring if (ring_indices.find(ring_index) == ring_indices.end() && ! geometry::covered_by(range::front(*it), exterior_ring, in_exterior_strategy)) { return visitor.template apply<failure_interior_rings_outside>(); } } // collect all rings (exterior and/or interior) that have turns for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit) { ring_indices.insert(tit->operations[0].seg_id.ring_index); ring_indices.insert(tit->operations[1].seg_id.ring_index); } typedef geometry::model::box<typename point_type<Polygon>::type> box_type; typedef partition_item<RingIterator, box_type> item_type; // put iterators for interior rings without turns in a vector std::vector<item_type> ring_iterators; ring_index = 0; for (RingIterator it = rings_first; it != rings_beyond; ++it, ++ring_index) { if (ring_indices.find(ring_index) == ring_indices.end()) { ring_iterators.push_back(item_type(it)); } } // prepare strategies typedef typename Strategy::envelope_strategy_type envelope_strategy_type; envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); typedef typename Strategy::disjoint_box_box_strategy_type disjoint_box_box_strategy_type; disjoint_box_box_strategy_type const disjoint_strategy = strategy.get_disjoint_box_box_strategy(); // call partition to check if interior rings are disjoint from // each other item_visitor_type<Strategy> item_visitor(strategy); geometry::partition < box_type >::apply(ring_iterators, item_visitor, expand_box < envelope_strategy_type >(envelope_strategy), overlaps_box < envelope_strategy_type, disjoint_box_box_strategy_type >(envelope_strategy, disjoint_strategy)); if (item_visitor.items_overlap) { return visitor.template apply<failure_nested_interior_rings>(); } else { return visitor.template apply<no_failure>(); } } template < typename InteriorRings, typename ExteriorRing, typename TurnIterator, typename VisitPolicy, typename Strategy > static inline bool are_holes_inside(InteriorRings const& interior_rings, ExteriorRing const& exterior_ring, TurnIterator first, TurnIterator beyond, VisitPolicy& visitor, Strategy const& strategy) { return are_holes_inside(boost::begin(interior_rings), boost::end(interior_rings), exterior_ring, first, beyond, visitor, strategy); } struct has_holes_inside { template <typename TurnIterator, typename VisitPolicy, typename Strategy> static inline bool apply(Polygon const& polygon, TurnIterator first, TurnIterator beyond, VisitPolicy& visitor, Strategy const& strategy) { return are_holes_inside(geometry::interior_rings(polygon), geometry::exterior_ring(polygon), first, beyond, visitor, strategy); } }; struct has_connected_interior { template <typename TurnIterator, typename VisitPolicy, typename Strategy> static inline bool apply(Polygon const& polygon, TurnIterator first, TurnIterator beyond, VisitPolicy& visitor, Strategy const& ) { boost::ignore_unused(visitor); typedef typename std::iterator_traits < TurnIterator >::value_type turn_type; typedef complement_graph < typename turn_type::point_type, typename Strategy::cs_tag > graph; graph g(geometry::num_interior_rings(polygon) + 1); for (TurnIterator tit = first; tit != beyond; ++tit) { typename graph::vertex_handle v1 = g.add_vertex ( tit->operations[0].seg_id.ring_index + 1 ); typename graph::vertex_handle v2 = g.add_vertex ( tit->operations[1].seg_id.ring_index + 1 ); typename graph::vertex_handle vip = g.add_vertex(tit->point); g.add_edge(v1, vip); g.add_edge(v2, vip); } #ifdef BOOST_GEOMETRY_TEST_DEBUG debug_print_complement_graph(std::cout, g); #endif // BOOST_GEOMETRY_TEST_DEBUG if (g.has_cycles()) { return visitor.template apply<failure_disconnected_interior>(); } else { return visitor.template apply<no_failure>(); } } }; public: template <typename VisitPolicy, typename Strategy> static inline bool apply(Polygon const& polygon, VisitPolicy& visitor, Strategy const& strategy) { if (! has_valid_rings::apply(polygon, visitor, strategy)) { return false; } if (BOOST_GEOMETRY_CONDITION(CheckRingValidityOnly)) { return true; } // compute turns and check if all are acceptable typedef debug_validity_phase<Polygon> debug_phase; debug_phase::apply(3); typedef has_valid_self_turns<Polygon, typename Strategy::cs_tag> has_valid_turns; std::deque<typename has_valid_turns::turn_type> turns; bool has_invalid_turns = ! has_valid_turns::apply(polygon, turns, visitor, strategy); debug_print_turns(turns.begin(), turns.end()); if (has_invalid_turns) { return false; } // check if all interior rings are inside the exterior ring debug_phase::apply(4); if (! has_holes_inside::apply(polygon, turns.begin(), turns.end(), visitor, strategy)) { return false; } // check whether the interior of the polygon is a connected set debug_phase::apply(5); return has_connected_interior::apply(polygon, turns.begin(), turns.end(), visitor, strategy); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A Polygon is always a simple geometric object provided that it is valid. // // Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1) template <typename Polygon, bool AllowEmptyMultiGeometries> struct is_valid < Polygon, polygon_tag, AllowEmptyMultiGeometries > : detail::is_valid::is_valid_polygon<Polygon> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP detail/is_valid/has_invalid_coordinate.hpp 0000644 00000010255 15125631656 0015016 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_HAS_INVALID_COORDINATE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_INVALID_COORDINATE_HPP #include <cstddef> #include <type_traits> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/iterators/point_iterator.hpp> #include <boost/geometry/views/detail/indexed_point_view.hpp> #include <boost/geometry/util/has_non_finite_coordinate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { struct always_valid { template <typename Geometry, typename VisitPolicy> static inline bool apply(Geometry const&, VisitPolicy& visitor) { return ! visitor.template apply<no_failure>(); } }; struct point_has_invalid_coordinate { template <typename Point, typename VisitPolicy> static inline bool apply(Point const& point, VisitPolicy& visitor) { boost::ignore_unused(visitor); return geometry::has_non_finite_coordinate(point) ? (! visitor.template apply<failure_invalid_coordinate>()) : (! visitor.template apply<no_failure>()); } template <typename Point> static inline bool apply(Point const& point) { return geometry::has_non_finite_coordinate(point); } }; struct indexed_has_invalid_coordinate { template <typename Geometry, typename VisitPolicy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) { geometry::detail::indexed_point_view<Geometry const, 0> p0(geometry); geometry::detail::indexed_point_view<Geometry const, 1> p1(geometry); return point_has_invalid_coordinate::apply(p0, visitor) || point_has_invalid_coordinate::apply(p1, visitor); } }; struct range_has_invalid_coordinate { struct point_has_valid_coordinates { template <typename Point> static inline bool apply(Point const& point) { return ! point_has_invalid_coordinate::apply(point); } }; template <typename Geometry, typename VisitPolicy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor) { boost::ignore_unused(visitor); bool const has_valid_coordinates = detail::check_iterator_range < point_has_valid_coordinates, true // do not consider an empty range as problematic >::apply(geometry::points_begin(geometry), geometry::points_end(geometry)); return has_valid_coordinates ? (! visitor.template apply<no_failure>()) : (! visitor.template apply<failure_invalid_coordinate>()); } }; template < typename Geometry, typename Tag = typename tag<Geometry>::type, bool HasFloatingPointCoordinates = std::is_floating_point < typename coordinate_type<Geometry>::type >::value > struct has_invalid_coordinate : range_has_invalid_coordinate {}; template <typename Geometry, typename Tag> struct has_invalid_coordinate<Geometry, Tag, false> : always_valid {}; template <typename Point> struct has_invalid_coordinate<Point, point_tag, true> : point_has_invalid_coordinate {}; template <typename Segment> struct has_invalid_coordinate<Segment, segment_tag, true> : indexed_has_invalid_coordinate {}; template <typename Box> struct has_invalid_coordinate<Box, box_tag, true> : indexed_has_invalid_coordinate {}; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_INVALID_COORDINATE_HPP detail/is_valid/interface.hpp 0000644 00000021556 15125631656 0012274 0 ustar 00 // Boost.Geometry // Copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP #include <sstream> #include <string> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/policies/is_valid/failing_reason_policy.hpp> #include <boost/geometry/policies/is_valid/failure_type_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/intersection.hpp> namespace boost { namespace geometry { namespace resolve_strategy { struct is_valid { template <typename Geometry, typename VisitPolicy, typename Strategy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy); } template <typename Geometry, typename VisitPolicy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, default_strategy) { // NOTE: Currently the strategy is only used for Areal geometries typedef typename strategy::intersection::services::default_strategy < typename cs_tag<Geometry>::type >::type strategy_type; return dispatch::is_valid<Geometry>::apply(geometry, visitor, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct is_valid { template <typename VisitPolicy, typename Strategy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { concepts::check<Geometry const>(); return resolve_strategy::is_valid::apply(geometry, visitor, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_valid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename VisitPolicy, typename Strategy> struct visitor : boost::static_visitor<bool> { visitor(VisitPolicy& policy, Strategy const& strategy) : m_policy(policy) , m_strategy(strategy) {} template <typename Geometry> bool operator()(Geometry const& geometry) const { return is_valid<Geometry>::apply(geometry, m_policy, m_strategy); } VisitPolicy& m_policy; Strategy const& m_strategy; }; template <typename VisitPolicy, typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, VisitPolicy& policy_visitor, Strategy const& strategy) { return boost::apply_visitor(visitor<VisitPolicy, Strategy>(policy_visitor, strategy), geometry); } }; } // namespace resolve_variant // Undocumented for now template <typename Geometry, typename VisitPolicy, typename Strategy> inline bool is_valid(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); } /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Is_valid} \param geometry \param_geometry \param strategy \param_strategy{is_valid} \return \return_check{is valid (in the OGC sense); furthermore, the following geometries are considered valid: multi-geometries with no elements, linear geometries containing spikes, areal geometries with duplicate (consecutive) points} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/is_valid.qbk]} */ template <typename Geometry, typename Strategy> inline bool is_valid(Geometry const& geometry, Strategy const& strategy) { is_valid_default_policy<> visitor; return resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); } /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_check{is valid (in the OGC sense); furthermore, the following geometries are considered valid: multi-geometries with no elements, linear geometries containing spikes, areal geometries with duplicate (consecutive) points} \qbk{[include reference/algorithms/is_valid.qbk]} */ template <typename Geometry> inline bool is_valid(Geometry const& geometry) { return is_valid(geometry, default_strategy()); } /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Is_valid} \param geometry \param_geometry \param failure An enumeration value indicating that the geometry is valid or not, and if not valid indicating the reason why \param strategy \param_strategy{is_valid} \return \return_check{is valid (in the OGC sense); furthermore, the following geometries are considered valid: multi-geometries with no elements, linear geometries containing spikes, areal geometries with duplicate (consecutive) points} \qbk{distinguish,with failure value and strategy} \qbk{[include reference/algorithms/is_valid_with_failure.qbk]} */ template <typename Geometry, typename Strategy> inline bool is_valid(Geometry const& geometry, validity_failure_type& failure, Strategy const& strategy) { failure_type_policy<> visitor; bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); failure = visitor.failure(); return result; } /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \param geometry \param_geometry \param failure An enumeration value indicating that the geometry is valid or not, and if not valid indicating the reason why \return \return_check{is valid (in the OGC sense); furthermore, the following geometries are considered valid: multi-geometries with no elements, linear geometries containing spikes, areal geometries with duplicate (consecutive) points} \qbk{distinguish,with failure value} \qbk{[include reference/algorithms/is_valid_with_failure.qbk]} */ template <typename Geometry> inline bool is_valid(Geometry const& geometry, validity_failure_type& failure) { return is_valid(geometry, failure, default_strategy()); } /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Is_valid} \param geometry \param_geometry \param message A string containing a message stating if the geometry is valid or not, and if not valid a reason why \param strategy \param_strategy{is_valid} \return \return_check{is valid (in the OGC sense); furthermore, the following geometries are considered valid: multi-geometries with no elements, linear geometries containing spikes, areal geometries with duplicate (consecutive) points} \qbk{distinguish,with message and strategy} \qbk{[include reference/algorithms/is_valid_with_message.qbk]} */ template <typename Geometry, typename Strategy> inline bool is_valid(Geometry const& geometry, std::string& message, Strategy const& strategy) { std::ostringstream stream; failing_reason_policy<> visitor(stream); bool result = resolve_variant::is_valid<Geometry>::apply(geometry, visitor, strategy); message = stream.str(); return result; } /*! \brief \brief_check{is valid (in the OGC sense)} \ingroup is_valid \tparam Geometry \tparam_geometry \param geometry \param_geometry \param message A string containing a message stating if the geometry is valid or not, and if not valid a reason why \return \return_check{is valid (in the OGC sense); furthermore, the following geometries are considered valid: multi-geometries with no elements, linear geometries containing spikes, areal geometries with duplicate (consecutive) points} \qbk{distinguish,with message} \qbk{[include reference/algorithms/is_valid_with_message.qbk]} */ template <typename Geometry> inline bool is_valid(Geometry const& geometry, std::string& message) { return is_valid(geometry, message, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_INTERFACE_HPP detail/is_valid/segment.hpp 0000644 00000005005 15125631656 0011765 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP #include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A segment is a curve. // A curve is simple if it does not pass through the same point twice, // with the possible exception of its two endpoints // A curve is 1-dimensional, hence we have to check is the two // endpoints of the segment coincide, since in this case it is // 0-dimensional. // // Reference: OGC 06-103r4 (6.1.6.1) template <typename Segment> struct is_valid<Segment, segment_tag> { template <typename VisitPolicy, typename Strategy> static inline bool apply(Segment const& segment, VisitPolicy& visitor, Strategy const&) { typedef typename Strategy::equals_point_point_strategy_type eq_pp_strategy_type; boost::ignore_unused(visitor); typename point_type<Segment>::type p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); if (detail::is_valid::has_invalid_coordinate < Segment >::apply(segment, visitor)) { return false; } else if (! geometry::detail::equals::equals_point_point( p[0], p[1], eq_pp_strategy_type())) { return visitor.template apply<no_failure>(); } else { return visitor.template apply<failure_wrong_topological_dimension>(); } } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP detail/is_valid/has_valid_self_turns.hpp 0000644 00000007462 15125631656 0014532 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP #include <vector> #include <boost/core/ignore_unused.hpp> #include <boost/range/empty.hpp> #include <boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/policies/predicate_based_interrupt_policy.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template < typename Geometry, typename CSTag > class has_valid_self_turns { private: typedef typename point_type<Geometry>::type point_type; typedef typename geometry::rescale_policy_type < point_type, CSTag >::type rescale_policy_type; typedef detail::overlay::get_turn_info < detail::overlay::assign_null_policy > turn_policy; public: typedef detail::overlay::turn_info < point_type, typename segment_ratio_type < point_type, rescale_policy_type >::type > turn_type; // returns true if all turns are valid template <typename Turns, typename VisitPolicy, typename Strategy> static inline bool apply(Geometry const& geometry, Turns& turns, VisitPolicy& visitor, Strategy const& strategy) { boost::ignore_unused(visitor); rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry, strategy); detail::overlay::stateless_predicate_based_interrupt_policy < is_acceptable_turn<Geometry> > interrupt_policy; // Calculate self-turns, skipping adjacent segments detail::self_get_turn_points::self_turns<false, turn_policy>(geometry, strategy, robust_policy, turns, interrupt_policy, 0, true); if (interrupt_policy.has_intersections) { BOOST_GEOMETRY_ASSERT(! boost::empty(turns)); return visitor.template apply<failure_self_intersections>(turns); } else { return visitor.template apply<no_failure>(); } } // returns true if all turns are valid template <typename VisitPolicy, typename Strategy> static inline bool apply(Geometry const& geometry, VisitPolicy& visitor, Strategy const& strategy) { std::vector<turn_type> turns; return apply(geometry, turns, visitor, strategy); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_VALID_SELF_TURNS_HPP detail/is_valid/has_spikes.hpp 0000644 00000014311 15125631656 0012454 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_HAS_SPIKES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP #include <algorithm> #include <type_traits> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/rbegin.hpp> #include <boost/range/rend.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/policies/is_valid/default_policy.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> #include <boost/geometry/io/dsv/write.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { template <typename Point, typename Strategy> struct equal_to { Point const& m_point; equal_to(Point const& point) : m_point(point) {} template <typename OtherPoint> inline bool operator()(OtherPoint const& other) const { return geometry::detail::equals::equals_point_point(m_point, other, Strategy()); } }; template <typename Point, typename Strategy> struct not_equal_to { Point const& m_point; not_equal_to(Point const& point) : m_point(point) {} template <typename OtherPoint> inline bool operator()(OtherPoint const& other) const { return ! geometry::detail::equals::equals_point_point(other, m_point, Strategy()); } }; template <typename Range, closure_selector Closure> struct has_spikes { template <typename Iterator, typename SideStrategy> static inline Iterator find_different_from_first(Iterator first, Iterator last, SideStrategy const& ) { typedef not_equal_to < typename point_type<Range>::type, typename SideStrategy::equals_point_point_strategy_type > not_equal; BOOST_GEOMETRY_ASSERT(first != last); Iterator second = first; ++second; return std::find_if(second, last, not_equal(*first)); } template <typename View, typename VisitPolicy, typename SideStrategy> static inline bool apply_at_closure(View const& view, VisitPolicy& visitor, SideStrategy const& strategy, bool is_linear) { boost::ignore_unused(visitor); typedef typename boost::range_iterator<View const>::type iterator; iterator cur = boost::begin(view); typename boost::range_reverse_iterator < View const >::type prev = find_different_from_first(boost::rbegin(view), boost::rend(view), strategy); iterator next = find_different_from_first(cur, boost::end(view), strategy); if (detail::is_spike_or_equal(*next, *cur, *prev, strategy)) { return ! visitor.template apply<failure_spikes>(is_linear, *cur); } else { return ! visitor.template apply<no_failure>(); } } template <typename VisitPolicy, typename SideStrategy> static inline bool apply(Range const& range, VisitPolicy& visitor, SideStrategy const& strategy) { boost::ignore_unused(visitor); typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename boost::range_iterator<view_type const>::type iterator; bool const is_linestring = std::is_same<typename tag<Range>::type, linestring_tag>::value; view_type const view(range); iterator prev = boost::begin(view); iterator cur = find_different_from_first(prev, boost::end(view), strategy); if (cur == boost::end(view)) { // the range has only one distinct point, so it // cannot have a spike return ! visitor.template apply<no_failure>(); } iterator next = find_different_from_first(cur, boost::end(view), strategy); if (next == boost::end(view)) { // the range has only two distinct points, so it // cannot have a spike return ! visitor.template apply<no_failure>(); } while (next != boost::end(view)) { // Verify spike. TODO: this is a reverse order from expected // in is_spike_or_equal, but this order calls the side // strategy in the way to correctly detect the spikes, // also in geographic cases going over the pole if (detail::is_spike_or_equal(*next, *cur, *prev, strategy)) { return ! visitor.template apply<failure_spikes>(is_linestring, *cur); } prev = cur; cur = next; next = find_different_from_first(cur, boost::end(view), strategy); } if (geometry::detail::equals:: equals_point_point(range::front(view), range::back(view), strategy.get_equals_point_point_strategy())) { return apply_at_closure(view, visitor, strategy, is_linestring); } return ! visitor.template apply<no_failure>(); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP detail/is_valid/ring.hpp 0000644 00000020100 15125631656 0011253 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_VALID_RING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP #include <deque> #include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/order_as_direction.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/validity_failure_type.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/num_distinct_consecutive_points.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_invalid_coordinate.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp> #include <boost/geometry/algorithms/dispatch/is_valid.hpp> // TEMP - with UmberllaStrategy this will be not needed #include <boost/geometry/strategy/area.hpp> #include <boost/geometry/strategies/area/services.hpp> // TODO: use point_order instead of area #ifdef BOOST_GEOMETRY_TEST_DEBUG #include <boost/geometry/io/dsv/write.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_valid { // struct to check whether a ring is topologically closed template <typename Ring, closure_selector Closure /* open */> struct is_topologically_closed { template <typename VisitPolicy, typename EqPPStrategy> static inline bool apply(Ring const&, VisitPolicy& visitor, EqPPStrategy const&) { boost::ignore_unused(visitor); return visitor.template apply<no_failure>(); } }; template <typename Ring> struct is_topologically_closed<Ring, closed> { template <typename VisitPolicy, typename EqPPStrategy> static inline bool apply(Ring const& ring, VisitPolicy& visitor, EqPPStrategy const&) { boost::ignore_unused(visitor); if (geometry::detail::equals::equals_point_point(range::front(ring), range::back(ring), EqPPStrategy())) { return visitor.template apply<no_failure>(); } else { return visitor.template apply<failure_not_closed>(); } } }; template <typename ResultType, bool IsInteriorRing /* false */> struct ring_area_predicate { typedef std::greater<ResultType> type; }; template <typename ResultType> struct ring_area_predicate<ResultType, true> { typedef std::less<ResultType> type; }; template <typename Ring, bool IsInteriorRing> struct is_properly_oriented { template <typename VisitPolicy, typename Strategy> static inline bool apply(Ring const& ring, VisitPolicy& visitor, Strategy const& strategy) { boost::ignore_unused(visitor); typedef detail::area::ring_area < order_as_direction<geometry::point_order<Ring>::value>::value, geometry::closure<Ring>::value > ring_area_type; typedef typename Strategy::template area_strategy < Ring >::type::template result_type<Ring>::type area_result_type; typename ring_area_predicate < area_result_type, IsInteriorRing >::type predicate; // Check area area_result_type const zero = 0; area_result_type const area = ring_area_type::apply(ring, // TEMP - in the future (umbrella) strategy will be passed here geometry::strategies::area::services::strategy_converter < decltype(strategy.template get_area_strategy<Ring>()) >::get(strategy.template get_area_strategy<Ring>())); if (predicate(area, zero)) { return visitor.template apply<no_failure>(); } else { return visitor.template apply<failure_wrong_orientation>(); } } }; template < typename Ring, bool CheckSelfIntersections = true, bool IsInteriorRing = false > struct is_valid_ring { template <typename VisitPolicy, typename Strategy> static inline bool apply(Ring const& ring, VisitPolicy& visitor, Strategy const& strategy) { typedef typename Strategy::cs_tag cs_tag; // return invalid if any of the following condition holds: // (a) the ring's point coordinates are not invalid (e.g., NaN) // (b) the ring's size is below the minimal one // (c) the ring consists of at most two distinct points // (d) the ring is not topologically closed // (e) the ring has spikes // (f) the ring has duplicate points (if AllowDuplicates is false) // (g) the boundary of the ring has self-intersections // (h) the order of the points is inconsistent with the defined order // // Note: no need to check if the area is zero. If this is the // case, then the ring must have at least two spikes, which is // checked by condition (d). if (has_invalid_coordinate<Ring>::apply(ring, visitor)) { return false; } closure_selector const closure = geometry::closure<Ring>::value; typedef typename closeable_view<Ring const, closure>::type view_type; if (boost::size(ring) < core_detail::closure::minimum_ring_size<closure>::value) { return visitor.template apply<failure_few_points>(); } view_type const view(ring); if (detail::num_distinct_consecutive_points < view_type, 4u, true, not_equal_to < typename point_type<Ring>::type, typename Strategy::equals_point_point_strategy_type > >::apply(view) < 4u) { return visitor.template apply<failure_wrong_topological_dimension>(); } return is_topologically_closed<Ring, closure>::apply(ring, visitor, strategy.get_equals_point_point_strategy()) && ! has_duplicates<Ring, closure, cs_tag>::apply(ring, visitor) && ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy()) && (! CheckSelfIntersections || has_valid_self_turns<Ring, typename Strategy::cs_tag>::apply(ring, visitor, strategy)) && is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy); } }; }} // namespace detail::is_valid #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A Ring is a Polygon with exterior boundary only. // The Ring's boundary must be a LinearRing (see OGC 06-103-r4, // 6.1.7.1, for the definition of LinearRing) // // Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) template <typename Ring, bool AllowEmptyMultiGeometries> struct is_valid < Ring, ring_tag, AllowEmptyMultiGeometries > : detail::is_valid::is_valid_ring<Ring> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP detail/intersection/implementation.hpp 0000644 00000001646 15125631656 0014273 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/intersection/areal_areal.hpp> #include <boost/geometry/algorithms/detail/intersection/box_box.hpp> #include <boost/geometry/algorithms/detail/intersection/multi.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_IMPLEMENTATION_HPP detail/intersection/areal_areal.hpp 0000644 00000023225 15125631656 0013473 0 ustar 00 // Boost.Geometry // Copyright (c) 2020, 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_DETAIL_INTERSECTION_AREAL_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_AREAL_AREAL_HPP #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/detail/intersection/interface.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template < typename GeometryOut, typename OutTag = typename geometry::detail::setop_insert_output_tag < typename geometry::detail::output_geometry_value < GeometryOut >::type >::type > struct intersection_areal_areal_ { template < typename Areal1, typename Areal2, typename RobustPolicy, typename Strategy > static inline void apply(Areal1 const& areal1, Areal2 const& areal2, RobustPolicy const& robust_policy, GeometryOut& geometry_out, Strategy const& strategy) { geometry::dispatch::intersection_insert < Areal1, Areal2, typename boost::range_value<GeometryOut>::type, overlay_intersection >::apply(areal1, areal2, robust_policy, geometry::range::back_inserter(geometry_out), strategy); } }; // TODO: Ideally this should be done in one call of intersection_insert // just like it's done for all other combinations template <typename TupledOut> struct intersection_areal_areal_<TupledOut, tupled_output_tag> { template < typename Areal1, typename Areal2, typename RobustPolicy, typename Strategy > static inline void apply(Areal1 const& areal1, Areal2 const& areal2, RobustPolicy const& robust_policy, TupledOut& geometry_out, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_value < TupledOut >::type single_out; boost::ignore_unused < geometry::detail::expect_output < Areal1, Areal2, single_out, point_tag, linestring_tag, polygon_tag > >(); typedef geometry::detail::output_geometry_access < single_out, polygon_tag, polygon_tag > areal; typedef geometry::detail::output_geometry_access < single_out, linestring_tag, linestring_tag > linear; typedef geometry::detail::output_geometry_access < single_out, point_tag, point_tag > pointlike; typedef typename geometry::tuples::element < areal::index, TupledOut >::type areal_out_type; typedef typename geometry::tuples::element < pointlike::index, TupledOut >::type pointlike_out_type; // NOTE: The same robust_policy is used in each call of // intersection_insert. Is that correct? // A * A -> A call_intersection(areal1, areal2, robust_policy, areal::get(geometry_out), strategy); bool const is_areal_empty = boost::empty(areal::get(geometry_out)); TupledOut temp_out; // L * L -> (L, P) call_intersection(geometry::detail::boundary_view<Areal1 const>(areal1), geometry::detail::boundary_view<Areal2 const>(areal2), robust_policy, ! is_areal_empty ? temp_out : geometry_out, strategy); if (! is_areal_empty) { // NOTE: the original areal geometry could be used instead of boundary here // however this results in static assert failure related to rescale policy typedef geometry::detail::boundary_view < areal_out_type const > areal_out_boundary_type; areal_out_boundary_type areal_out_boundary(areal::get(geometry_out)); // L - L -> L call_difference(linear::get(temp_out), areal_out_boundary, robust_policy, linear::get(geometry_out), strategy); // P - L -> P call_difference(pointlike::get(temp_out), areal_out_boundary, robust_policy, pointlike::get(geometry_out), strategy.template get_point_in_geometry_strategy < pointlike_out_type, areal_out_boundary_type >()); } return; } private: template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename GeometryOut, typename Strategy > static inline void call_intersection(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, GeometryOut& geometry_out, Strategy const& strategy) { geometry::dispatch::intersection_insert < Geometry1, Geometry2, typename geometry::detail::output_geometry_value < GeometryOut >::type, overlay_intersection >::apply(geometry1, geometry2, robust_policy, geometry::detail::output_geometry_back_inserter(geometry_out), strategy); } template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename GeometryOut, typename Strategy > static inline void call_difference(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, GeometryOut& geometry_out, Strategy const& strategy) { geometry::dispatch::intersection_insert < Geometry1, Geometry2, typename boost::range_value<GeometryOut>::type, overlay_difference >::apply(geometry1, geometry2, robust_policy, geometry::range::back_inserter(geometry_out), strategy); } }; struct intersection_areal_areal { template < typename Areal1, typename Areal2, typename RobustPolicy, typename GeometryOut, typename Strategy > static inline bool apply(Areal1 const& areal1, Areal2 const& areal2, RobustPolicy const& robust_policy, GeometryOut& geometry_out, Strategy const& strategy) { intersection_areal_areal_ < GeometryOut >::apply(areal1, areal2, robust_policy, geometry_out, strategy); return true; } }; }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Polygon1, typename Polygon2 > struct intersection < Polygon1, Polygon2, polygon_tag, polygon_tag, false > : detail::intersection::intersection_areal_areal {}; template < typename Polygon, typename Ring > struct intersection < Polygon, Ring, polygon_tag, ring_tag, false > : detail::intersection::intersection_areal_areal {}; template < typename Ring1, typename Ring2 > struct intersection < Ring1, Ring2, ring_tag, ring_tag, false > : detail::intersection::intersection_areal_areal {}; template < typename Polygon, typename MultiPolygon > struct intersection < Polygon, MultiPolygon, polygon_tag, multi_polygon_tag, false > : detail::intersection::intersection_areal_areal {}; template < typename MultiPolygon, typename Ring > struct intersection < MultiPolygon, Ring, multi_polygon_tag, ring_tag, false > : detail::intersection::intersection_areal_areal {}; template < typename MultiPolygon1, typename MultiPolygon2 > struct intersection < MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag, false > : detail::intersection::intersection_areal_areal {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_AREAL_AREAL_HPP detail/intersection/interface.hpp 0000644 00000031264 15125631656 0013205 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014, 2017, 2019. // Modifications copyright (c) 2014-2019, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> #include <boost/geometry/algorithms/detail/tupled_output.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // By default, all is forwarded to the intersection_insert-dispatcher template < typename Geometry1, typename Geometry2, typename Tag1 = typename geometry::tag<Geometry1>::type, typename Tag2 = typename geometry::tag<Geometry2>::type, bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value > struct intersection { template <typename RobustPolicy, typename GeometryOut, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, GeometryOut& geometry_out, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_value < GeometryOut >::type SingleOut; intersection_insert < Geometry1, Geometry2, SingleOut, overlay_intersection >::apply(geometry1, geometry2, robust_policy, geometry::detail::output_geometry_back_inserter(geometry_out), strategy); return true; } }; // If reversal is needed, perform it template < typename Geometry1, typename Geometry2, typename Tag1, typename Tag2 > struct intersection < Geometry1, Geometry2, Tag1, Tag2, true > : intersection<Geometry2, Geometry1, Tag2, Tag1, false> { template <typename RobustPolicy, typename GeometryOut, typename Strategy> static inline bool apply( Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, GeometryOut& out, Strategy const& strategy) { return intersection < Geometry2, Geometry1, Tag2, Tag1, false >::apply(g2, g1, robust_policy, out, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct intersection { template < typename Geometry1, typename Geometry2, typename GeometryOut, typename Strategy > static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, GeometryOut & geometry_out, Strategy const& strategy) { typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return dispatch::intersection < Geometry1, Geometry2 >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy); } template < typename Geometry1, typename Geometry2, typename GeometryOut > static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, GeometryOut & geometry_out, default_strategy) { typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename geometry::cs_tag<Geometry1>::type >::type rescale_policy_type; typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return dispatch::intersection < Geometry1, Geometry2 >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy); } }; } // resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct intersection { template <typename GeometryOut, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, GeometryOut& geometry_out, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return resolve_strategy::intersection::apply(geometry1, geometry2, geometry_out, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename GeometryOut, typename Strategy> struct visitor: static_visitor<bool> { Geometry2 const& m_geometry2; GeometryOut& m_geometry_out; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, GeometryOut& geometry_out, Strategy const& strategy) : m_geometry2(geometry2) , m_geometry_out(geometry_out) , m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return intersection < Geometry1, Geometry2 >::apply(geometry1, m_geometry2, m_geometry_out, m_strategy); } }; template <typename GeometryOut, typename Strategy> static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, GeometryOut& geometry_out, Strategy const& strategy) { return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry2, geometry_out, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct intersection<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename GeometryOut, typename Strategy> struct visitor: static_visitor<bool> { Geometry1 const& m_geometry1; GeometryOut& m_geometry_out; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, GeometryOut& geometry_out, Strategy const& strategy) : m_geometry1(geometry1) , m_geometry_out(geometry_out) , m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return intersection < Geometry1, Geometry2 >::apply(m_geometry1, geometry2, m_geometry_out, m_strategy); } }; template <typename GeometryOut, typename Strategy> static inline bool apply(Geometry1 const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, GeometryOut& geometry_out, Strategy const& strategy) { return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry1, geometry_out, strategy), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct intersection<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename GeometryOut, typename Strategy> struct visitor: static_visitor<bool> { GeometryOut& m_geometry_out; Strategy const& m_strategy; visitor(GeometryOut& geometry_out, Strategy const& strategy) : m_geometry_out(geometry_out) , m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return intersection < Geometry1, Geometry2 >::apply(geometry1, geometry2, m_geometry_out, m_strategy); } }; template <typename GeometryOut, typename Strategy> static inline bool apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, GeometryOut& geometry_out, Strategy const& strategy) { return boost::apply_visitor(visitor<GeometryOut, Strategy>(geometry_out, strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_calc2{intersection} \ingroup intersection \details \details_calc2{intersection, spatial set theoretic intersection}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box) \tparam Strategy \tparam_strategy{Intersection} \param geometry1 \param_geometry \param geometry2 \param_geometry \param geometry_out The output geometry, either a multi_point, multi_polygon, multi_linestring, or a box (for intersection of two boxes) \param strategy \param_strategy{intersection} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename Geometry1, typename Geometry2, typename GeometryOut, typename Strategy > inline bool intersection(Geometry1 const& geometry1, Geometry2 const& geometry2, GeometryOut& geometry_out, Strategy const& strategy) { return resolve_variant::intersection < Geometry1, Geometry2 >::apply(geometry1, geometry2, geometry_out, strategy); } /*! \brief \brief_calc2{intersection} \ingroup intersection \details \details_calc2{intersection, spatial set theoretic intersection}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam GeometryOut Collection of geometries (e.g. std::vector, std::deque, boost::geometry::multi*) of which the value_type fulfills a \p_l_or_c concept, or it is the output geometry (e.g. for a box) \param geometry1 \param_geometry \param geometry2 \param_geometry \param geometry_out The output geometry, either a multi_point, multi_polygon, multi_linestring, or a box (for intersection of two boxes) \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename Geometry1, typename Geometry2, typename GeometryOut > inline bool intersection(Geometry1 const& geometry1, Geometry2 const& geometry2, GeometryOut& geometry_out) { return resolve_variant::intersection < Geometry1, Geometry2 >::apply(geometry1, geometry2, geometry_out, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_INTERFACE_HPP detail/intersection/multi.hpp 0000644 00000041146 15125631656 0012377 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014, 2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP #include <type_traits> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/geometry_id.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> // TODO: those headers probably may be removed #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> #include <boost/geometry/algorithms/detail/intersection/interface.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/num_points.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template <typename PointOut> struct intersection_multi_linestring_multi_linestring_point { template < typename MultiLinestring1, typename MultiLinestring2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(MultiLinestring1 const& ml1, MultiLinestring2 const& ml2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Note, this loop is quadratic w.r.t. number of linestrings per input. // Future Enhancement: first do the sections of each, then intersect. for (typename boost::range_iterator < MultiLinestring1 const >::type it1 = boost::begin(ml1); it1 != boost::end(ml1); ++it1) { for (typename boost::range_iterator < MultiLinestring2 const >::type it2 = boost::begin(ml2); it2 != boost::end(ml2); ++it2) { out = intersection_linestring_linestring_point<PointOut> ::apply(*it1, *it2, robust_policy, out, strategy); } } return out; } }; template <typename PointOut> struct intersection_linestring_multi_linestring_point { template < typename Linestring, typename MultiLinestring, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linestring const& linestring, MultiLinestring const& ml, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { for (typename boost::range_iterator < MultiLinestring const >::type it = boost::begin(ml); it != boost::end(ml); ++it) { out = intersection_linestring_linestring_point<PointOut> ::apply(linestring, *it, robust_policy, out, strategy); } return out; } }; // This loop is quite similar to the loop above, but beacuse the iterator // is second (above) or first (below) argument, it is not trivial to merge them. template < bool ReverseAreal, typename LineStringOut, overlay_type OverlayType, bool FollowIsolatedPoints > struct intersection_of_multi_linestring_with_areal { template < typename MultiLinestring, typename Areal, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { for (typename boost::range_iterator < MultiLinestring const >::type it = boost::begin(ml); it != boost::end(ml); ++it) { out = intersection_of_linestring_with_areal < ReverseAreal, LineStringOut, OverlayType, FollowIsolatedPoints >::apply(*it, areal, robust_policy, out, strategy); } return out; } }; // This one calls the one above with reversed arguments template < bool ReverseAreal, typename LineStringOut, overlay_type OverlayType, bool FollowIsolatedPoints > struct intersection_of_areal_with_multi_linestring { template < typename Areal, typename MultiLinestring, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return intersection_of_multi_linestring_with_areal < ReverseAreal, LineStringOut, OverlayType, FollowIsolatedPoints >::apply(ml, areal, robust_policy, out, strategy); } }; template <typename LinestringOut> struct clip_multi_linestring { template < typename MultiLinestring, typename Box, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(MultiLinestring const& multi_linestring, Box const& box, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { typedef typename point_type<LinestringOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; for (typename boost::range_iterator<MultiLinestring const>::type it = boost::begin(multi_linestring); it != boost::end(multi_linestring); ++it) { out = detail::intersection::clip_range_with_box <LinestringOut>(box, *it, robust_policy, out, lb_strategy); } return out; } }; }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Linear template < typename MultiLinestring1, typename MultiLinestring2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < MultiLinestring1, MultiLinestring2, GeometryOut, OverlayType, Reverse1, Reverse2, multi_linestring_tag, multi_linestring_tag, point_tag, linear_tag, linear_tag, pointlike_tag > : detail::intersection::intersection_multi_linestring_multi_linestring_point < GeometryOut > {}; template < typename Linestring, typename MultiLinestring, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, MultiLinestring, GeometryOut, OverlayType, Reverse1, Reverse2, linestring_tag, multi_linestring_tag, point_tag, linear_tag, linear_tag, pointlike_tag > : detail::intersection::intersection_linestring_multi_linestring_point < GeometryOut > {}; template < typename MultiLinestring, typename Box, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < MultiLinestring, Box, GeometryOut, OverlayType, Reverse1, Reverse2, multi_linestring_tag, box_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::clip_multi_linestring < GeometryOut > {}; template < typename Linestring, typename MultiPolygon, typename GeometryOut, overlay_type OverlayType, bool ReverseLinestring, bool ReverseMultiPolygon > struct intersection_insert < Linestring, MultiPolygon, GeometryOut, OverlayType, ReverseLinestring, ReverseMultiPolygon, linestring_tag, multi_polygon_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_linestring_with_areal < ReverseMultiPolygon, GeometryOut, OverlayType, false > {}; // Derives from areal/mls because runtime arguments are in that order. // areal/mls reverses it itself to mls/areal template < typename Polygon, typename MultiLinestring, typename GeometryOut, overlay_type OverlayType, bool ReversePolygon, bool ReverseMultiLinestring > struct intersection_insert < Polygon, MultiLinestring, GeometryOut, OverlayType, ReversePolygon, ReverseMultiLinestring, polygon_tag, multi_linestring_tag, linestring_tag, areal_tag, linear_tag, linear_tag > : detail::intersection::intersection_of_areal_with_multi_linestring < ReversePolygon, GeometryOut, OverlayType, false > {}; template < typename MultiLinestring, typename Ring, typename GeometryOut, overlay_type OverlayType, bool ReverseMultiLinestring, bool ReverseRing > struct intersection_insert < MultiLinestring, Ring, GeometryOut, OverlayType, ReverseMultiLinestring, ReverseRing, multi_linestring_tag, ring_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_multi_linestring_with_areal < ReverseRing, GeometryOut, OverlayType, false > {}; template < typename MultiLinestring, typename Polygon, typename GeometryOut, overlay_type OverlayType, bool ReverseMultiLinestring, bool ReversePolygon > struct intersection_insert < MultiLinestring, Polygon, GeometryOut, OverlayType, ReverseMultiLinestring, ReversePolygon, multi_linestring_tag, polygon_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_multi_linestring_with_areal < ReversePolygon, GeometryOut, OverlayType, false > {}; template < typename MultiLinestring, typename MultiPolygon, typename GeometryOut, overlay_type OverlayType, bool ReverseMultiLinestring, bool ReverseMultiPolygon > struct intersection_insert < MultiLinestring, MultiPolygon, GeometryOut, OverlayType, ReverseMultiLinestring, ReverseMultiPolygon, multi_linestring_tag, multi_polygon_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_multi_linestring_with_areal < ReverseMultiPolygon, GeometryOut, OverlayType, false > {}; template < typename MultiLinestring, typename Ring, typename TupledOut, overlay_type OverlayType, bool ReverseMultiLinestring, bool ReverseRing > struct intersection_insert < MultiLinestring, Ring, TupledOut, OverlayType, ReverseMultiLinestring, ReverseRing, multi_linestring_tag, ring_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_multi_linestring_with_areal < ReverseRing, TupledOut, OverlayType, true > , detail::expect_output < MultiLinestring, Ring, TupledOut, // NOTE: points can be the result only in case of intersection. // TODO: union should require L and A std::conditional_t < (OverlayType == overlay_intersection), point_tag, void >, linestring_tag > {}; template < typename MultiLinestring, typename Polygon, typename TupledOut, overlay_type OverlayType, bool ReverseMultiLinestring, bool ReversePolygon > struct intersection_insert < MultiLinestring, Polygon, TupledOut, OverlayType, ReverseMultiLinestring, ReversePolygon, multi_linestring_tag, polygon_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_multi_linestring_with_areal < ReversePolygon, TupledOut, OverlayType, true > , detail::expect_output < MultiLinestring, Polygon, TupledOut, // NOTE: points can be the result only in case of intersection. // TODO: union should require L and A std::conditional_t < (OverlayType == overlay_intersection), point_tag, void >, linestring_tag > {}; template < typename Polygon, typename MultiLinestring, typename TupledOut, overlay_type OverlayType, bool ReversePolygon, bool ReverseMultiLinestring > struct intersection_insert < Polygon, MultiLinestring, TupledOut, OverlayType, ReversePolygon, ReverseMultiLinestring, polygon_tag, multi_linestring_tag, detail::tupled_output_tag, areal_tag, linear_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_areal_with_multi_linestring < ReversePolygon, TupledOut, OverlayType, true > , detail::expect_output < Polygon, MultiLinestring, TupledOut, // NOTE: points can be the result only in case of intersection. // TODO: union should require L and A // TODO: in general the result of difference should depend on the first argument // but this specialization calls L/A in reality so the first argument is linear. // So expect only L for difference? std::conditional_t < (OverlayType == overlay_intersection), point_tag, void >, linestring_tag > {}; template < typename MultiLinestring, typename MultiPolygon, typename TupledOut, overlay_type OverlayType, bool ReverseMultiLinestring, bool ReverseMultiPolygon > struct intersection_insert < MultiLinestring, MultiPolygon, TupledOut, OverlayType, ReverseMultiLinestring, ReverseMultiPolygon, multi_linestring_tag, multi_polygon_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_multi_linestring_with_areal < ReverseMultiPolygon, TupledOut, OverlayType, true > , detail::expect_output < MultiLinestring, MultiPolygon, TupledOut, // NOTE: points can be the result only in case of intersection. // TODO: union should require L and A std::conditional_t < (OverlayType == overlay_intersection), point_tag, void >, linestring_tag > {}; } // namespace dispatch #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_MULTI_HPP detail/intersection/box_box.hpp 0000644 00000002456 15125631656 0012706 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP #include <boost/geometry/algorithms/detail/intersection/interface.hpp> #include <boost/geometry/algorithms/detail/overlay/intersection_box_box.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Box1, typename Box2, bool Reverse > struct intersection < Box1, Box2, box_tag, box_tag, Reverse > : public detail::intersection::intersection_box_box < 0, geometry::dimension<Box1>::value > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_BOX_BOX_HPP detail/check_iterator_range.hpp 0000644 00000003734 15125631656 0012702 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP #include <boost/core/ignore_unused.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { // Check whether (each element of) an iterator range satisfies a given // predicate. // The predicate must be implemented as having a static apply unary // method that returns a bool. // By default an empty range is accepted template <typename Predicate, bool AllowEmptyRange = true> struct check_iterator_range { template <typename InputIterator> static inline bool apply(InputIterator first, InputIterator beyond) { for (InputIterator it = first; it != beyond; ++it) { if (! Predicate::apply(*it)) { return false; } } return AllowEmptyRange || first != beyond; } // version where we can pass a predicate object template <typename InputIterator> static inline bool apply(InputIterator first, InputIterator beyond, Predicate const& predicate) { // in case predicate's apply method is static, MSVC will // complain that predicate is not used boost::ignore_unused(predicate); for (InputIterator it = first; it != beyond; ++it) { if (! predicate.apply(*it)) { return false; } } return AllowEmptyRange || first != beyond; } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CHECK_ITERATOR_RANGE_HPP detail/equals/implementation.hpp 0000644 00000037466 15125631656 0013070 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP #include <cstddef> #include <type_traits> #include <vector> #include <boost/range/size.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> // For trivial checks #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/length.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/util/select_most_precise.hpp> #include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp> #include <boost/geometry/algorithms/detail/equals/interface.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/views/detail/indexed_point_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace equals { template < std::size_t Dimension, std::size_t DimensionCount > struct point_point { template <typename Point1, typename Point2, typename Strategy> static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& ) { return Strategy::apply(point1, point2); } }; template < std::size_t Dimension, std::size_t DimensionCount > struct box_box { template <typename Box1, typename Box2, typename Strategy> static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) { if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2)) || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2))) { return false; } return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy); } }; template <std::size_t DimensionCount> struct box_box<DimensionCount, DimensionCount> { template <typename Box1, typename Box2, typename Strategy> static inline bool apply(Box1 const& , Box2 const& , Strategy const& ) { return true; } }; struct segment_segment { template <typename Segment1, typename Segment2, typename Strategy> static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& strategy) { typename Strategy::point_in_point_strategy_type const& pt_pt_strategy = strategy.get_point_in_point_strategy(); return equals::equals_point_point( indexed_point_view<Segment1 const, 0>(segment1), indexed_point_view<Segment2 const, 0>(segment2), pt_pt_strategy) ? equals::equals_point_point( indexed_point_view<Segment1 const, 1>(segment1), indexed_point_view<Segment2 const, 1>(segment2), pt_pt_strategy) : ( equals::equals_point_point( indexed_point_view<Segment1 const, 0>(segment1), indexed_point_view<Segment2 const, 1>(segment2), pt_pt_strategy) && equals::equals_point_point( indexed_point_view<Segment1 const, 1>(segment1), indexed_point_view<Segment2 const, 0>(segment2), pt_pt_strategy) ); } }; struct area_check { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return geometry::math::equals( geometry::area(geometry1, strategy.template get_area_strategy<Geometry1>()), geometry::area(geometry2, strategy.template get_area_strategy<Geometry2>())); } }; struct length_check { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return geometry::math::equals( geometry::length(geometry1, strategy.template get_distance_strategy<Geometry1>()), geometry::length(geometry2, strategy.template get_distance_strategy<Geometry2>())); } }; template <typename Geometry1, typename Geometry2, typename IntersectionStrategy> struct collected_vector { typedef typename geometry::select_most_precise < typename select_coordinate_type < Geometry1, Geometry2 >::type, double >::type calculation_type; typedef geometry::collected_vector < calculation_type, Geometry1, typename IntersectionStrategy::side_strategy_type > type; }; template <typename TrivialCheck> struct equals_by_collection { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { if (! TrivialCheck::apply(geometry1, geometry2, strategy)) { return false; } typedef typename collected_vector < Geometry1, Geometry2, Strategy >::type collected_vector_type; std::vector<collected_vector_type> c1, c2; geometry::collect_vectors(c1, geometry1); geometry::collect_vectors(c2, geometry2); if (boost::size(c1) != boost::size(c2)) { return false; } std::sort(c1.begin(), c1.end()); std::sort(c2.begin(), c2.end()); // Just check if these vectors are equal. return std::equal(c1.begin(), c1.end(), c2.begin()); } }; template<typename Geometry1, typename Geometry2> struct equals_by_relate : detail::relate::relate_impl < detail::de9im::static_mask_equals_type, Geometry1, Geometry2 > {}; // If collect_vectors which is a SideStrategy-dispatched optimization // is implemented in a way consistent with the Intersection/Side Strategy // then collect_vectors is used, otherwise relate is used. // NOTE: the result could be conceptually different for invalid // geometries in different coordinate systems because collect_vectors // and relate treat invalid geometries differently. template<typename TrivialCheck> struct equals_by_collection_or_relate { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef std::is_base_of < nyi::not_implemented_tag, typename collected_vector < Geometry1, Geometry2, Strategy >::type > enable_relate_type; return apply(geometry1, geometry2, strategy, enable_relate_type()); } private: template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy, std::false_type /*enable_relate*/) { return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy, std::true_type /*enable_relate*/) { return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } }; struct equals_always_false { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const& ) { return false; } }; }} // namespace detail::equals #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse> struct equals<P1, P2, point_tag, point_tag, pointlike_tag, pointlike_tag, DimensionCount, Reverse> : detail::equals::point_point<0, DimensionCount> {}; template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse> struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, pointlike_tag, pointlike_tag, DimensionCount, Reverse> : detail::equals::equals_by_relate<MultiPoint1, MultiPoint2> {}; template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse> struct equals<Point, MultiPoint, point_tag, multi_point_tag, pointlike_tag, pointlike_tag, DimensionCount, Reverse> : detail::equals::equals_by_relate<Point, MultiPoint> {}; template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse> struct equals<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, DimensionCount, Reverse> : detail::equals::box_box<0, DimensionCount> {}; template <typename Ring1, typename Ring2, bool Reverse> struct equals<Ring1, Ring2, ring_tag, ring_tag, areal_tag, areal_tag, 2, Reverse> : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename Polygon1, typename Polygon2, bool Reverse> struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, areal_tag, areal_tag, 2, Reverse> : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename Polygon, typename Ring, bool Reverse> struct equals<Polygon, Ring, polygon_tag, ring_tag, areal_tag, areal_tag, 2, Reverse> : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename Ring, typename Box, bool Reverse> struct equals<Ring, Box, ring_tag, box_tag, areal_tag, areal_tag, 2, Reverse> : detail::equals::equals_by_collection<detail::equals::area_check> {}; template <typename Polygon, typename Box, bool Reverse> struct equals<Polygon, Box, polygon_tag, box_tag, areal_tag, areal_tag, 2, Reverse> : detail::equals::equals_by_collection<detail::equals::area_check> {}; template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse> struct equals<Segment1, Segment2, segment_tag, segment_tag, linear_tag, linear_tag, DimensionCount, Reverse> : detail::equals::segment_segment {}; template <typename LineString1, typename LineString2, bool Reverse> struct equals<LineString1, LineString2, linestring_tag, linestring_tag, linear_tag, linear_tag, 2, Reverse> : detail::equals::equals_by_relate<LineString1, LineString2> {}; template <typename LineString, typename MultiLineString, bool Reverse> struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, linear_tag, linear_tag, 2, Reverse> : detail::equals::equals_by_relate<LineString, MultiLineString> {}; template <typename MultiLineString1, typename MultiLineString2, bool Reverse> struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, linear_tag, linear_tag, 2, Reverse> : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2> {}; template <typename LineString, typename Segment, bool Reverse> struct equals<LineString, Segment, linestring_tag, segment_tag, linear_tag, linear_tag, 2, Reverse> : detail::equals::equals_by_relate<LineString, Segment> {}; template <typename MultiLineString, typename Segment, bool Reverse> struct equals<MultiLineString, Segment, multi_linestring_tag, segment_tag, linear_tag, linear_tag, 2, Reverse> : detail::equals::equals_by_relate<MultiLineString, Segment> {}; template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse> struct equals < MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag, areal_tag, areal_tag, 2, Reverse > : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename Polygon, typename MultiPolygon, bool Reverse> struct equals < Polygon, MultiPolygon, polygon_tag, multi_polygon_tag, areal_tag, areal_tag, 2, Reverse > : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; template <typename MultiPolygon, typename Ring, bool Reverse> struct equals < MultiPolygon, Ring, multi_polygon_tag, ring_tag, areal_tag, areal_tag, 2, Reverse > : detail::equals::equals_by_collection_or_relate<detail::equals::area_check> {}; // NOTE: degenerated linear geometries, e.g. segment or linestring containing // 2 equal points, are considered to be invalid. Though theoretically // degenerated segments and linestrings could be treated as points and // multi-linestrings as multi-points. // This reasoning could also be applied to boxes. template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount> struct equals<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, linear_tag, DimensionCount, false> : detail::equals::equals_always_false {}; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount> struct equals<Geometry1, Geometry2, Tag1, Tag2, linear_tag, pointlike_tag, DimensionCount, false> : detail::equals::equals_always_false {}; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount> struct equals<Geometry1, Geometry2, Tag1, Tag2, pointlike_tag, areal_tag, DimensionCount, false> : detail::equals::equals_always_false {}; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount> struct equals<Geometry1, Geometry2, Tag1, Tag2, areal_tag, pointlike_tag, DimensionCount, false> : detail::equals::equals_always_false {}; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount> struct equals<Geometry1, Geometry2, Tag1, Tag2, linear_tag, areal_tag, DimensionCount, false> : detail::equals::equals_always_false {}; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, std::size_t DimensionCount> struct equals<Geometry1, Geometry2, Tag1, Tag2, areal_tag, linear_tag, DimensionCount, false> : detail::equals::equals_always_false {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP detail/equals/collect_vectors.hpp 0000644 00000042303 15125631656 0013217 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017, 2019. // Modifications copyright (c) 2017, 2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP #include <boost/numeric/conversion/cast.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/normalize.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/formulas/spherical.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> #include <boost/geometry/strategies/spherical/ssf.hpp> #include <boost/geometry/strategies/normalize.hpp> namespace boost { namespace geometry { // Since these vectors (though ray would be a better name) are used in the // implementation of equals() for Areal geometries the internal representation // should be consistent with the side strategy. template < typename T, typename Geometry, typename SideStrategy, typename CSTag = typename cs_tag<Geometry>::type > struct collected_vector : nyi::not_implemented_tag {}; // compatible with side_by_triangle cartesian strategy template <typename T, typename Geometry, typename CT, typename CSTag> struct collected_vector < T, Geometry, strategy::side::side_by_triangle<CT>, CSTag > { typedef T type; inline collected_vector() {} inline collected_vector(T const& px, T const& py, T const& pdx, T const& pdy) : x(px) , y(py) , dx(pdx) , dy(pdy) //, dx_0(dx) //, dy_0(dy) {} template <typename Point> inline collected_vector(Point const& p1, Point const& p2) : x(get<0>(p1)) , y(get<1>(p1)) , dx(get<0>(p2) - x) , dy(get<1>(p2) - y) //, dx_0(dx) //, dy_0(dy) {} bool normalize() { T magnitude = math::sqrt( boost::numeric_cast<T>(dx * dx + dy * dy)); // NOTE: shouldn't here math::equals() be called? if (magnitude > 0) { dx /= magnitude; dy /= magnitude; return true; } return false; } // For sorting inline bool operator<(collected_vector const& other) const { if (math::equals(x, other.x)) { if (math::equals(y, other.y)) { if (math::equals(dx, other.dx)) { return dy < other.dy; } return dx < other.dx; } return y < other.y; } return x < other.x; } inline bool next_is_collinear(collected_vector const& other) const { return same_direction(other); } // For std::equals inline bool operator==(collected_vector const& other) const { return math::equals(x, other.x) && math::equals(y, other.y) && same_direction(other); } private: inline bool same_direction(collected_vector const& other) const { // For high precision arithmetic, we have to be // more relaxed then using == // Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) ) // is not always true (at least, not for some user defined types) return math::equals_with_epsilon(dx, other.dx) && math::equals_with_epsilon(dy, other.dy); } T x, y; T dx, dy; //T dx_0, dy_0; }; // Compatible with spherical_side_formula which currently // is the default spherical_equatorial and geographic strategy // so CSTag is spherical_equatorial_tag or geographic_tag template <typename T, typename Geometry, typename CT, typename CSTag> struct collected_vector < T, Geometry, strategy::side::spherical_side_formula<CT>, CSTag > { typedef T type; typedef typename geometry::detail::cs_angular_units<Geometry>::type units_type; typedef model::point<T, 2, cs::spherical_equatorial<units_type> > point_type; typedef model::point<T, 3, cs::cartesian> vector_type; collected_vector() {} template <typename Point> collected_vector(Point const& p1, Point const& p2) : origin(get<0>(p1), get<1>(p1)) { origin = detail::return_normalized<point_type>( origin, strategy::normalize::spherical_point()); using namespace geometry::formula; prev = sph_to_cart3d<vector_type>(p1); next = sph_to_cart3d<vector_type>(p2); direction = cross_product(prev, next); } bool normalize() { T magnitude_sqr = dot_product(direction, direction); // NOTE: shouldn't here math::equals() be called? if (magnitude_sqr > 0) { divide_value(direction, math::sqrt(magnitude_sqr)); return true; } return false; } bool operator<(collected_vector const& other) const { if (math::equals(get<0>(origin), get<0>(other.origin))) { if (math::equals(get<1>(origin), get<1>(other.origin))) { if (math::equals(get<0>(direction), get<0>(other.direction))) { if (math::equals(get<1>(direction), get<1>(other.direction))) { return get<2>(direction) < get<2>(other.direction); } return get<1>(direction) < get<1>(other.direction); } return get<0>(direction) < get<0>(other.direction); } return get<1>(origin) < get<1>(other.origin); } return get<0>(origin) < get<0>(other.origin); } // For consistency with side and intersection strategies used by relops // IMPORTANT: this method should be called for previous vector // and next vector should be passed as parameter bool next_is_collinear(collected_vector const& other) const { return formula::sph_side_value(direction, other.next) == 0; } // For std::equals bool operator==(collected_vector const& other) const { return math::equals(get<0>(origin), get<0>(other.origin)) && math::equals(get<1>(origin), get<1>(other.origin)) && is_collinear(other); } private: // For consistency with side and intersection strategies used by relops bool is_collinear(collected_vector const& other) const { return formula::sph_side_value(direction, other.prev) == 0 && formula::sph_side_value(direction, other.next) == 0; } /*bool same_direction(collected_vector const& other) const { return math::equals_with_epsilon(get<0>(direction), get<0>(other.direction)) && math::equals_with_epsilon(get<1>(direction), get<1>(other.direction)) && math::equals_with_epsilon(get<2>(direction), get<2>(other.direction)); }*/ point_type origin; // used for sorting and equality check vector_type direction; // used for sorting, only in operator< vector_type prev; // used for collinearity check, only in operator== vector_type next; // used for collinearity check }; // Specialization for spherical polar template <typename T, typename Geometry, typename CT> struct collected_vector < T, Geometry, strategy::side::spherical_side_formula<CT>, spherical_polar_tag > : public collected_vector < T, Geometry, strategy::side::spherical_side_formula<CT>, spherical_equatorial_tag > { typedef collected_vector < T, Geometry, strategy::side::spherical_side_formula<CT>, spherical_equatorial_tag > base_type; collected_vector() {} template <typename Point> collected_vector(Point const& p1, Point const& p2) : base_type(to_equatorial(p1), to_equatorial(p2)) {} private: template <typename Point> Point to_equatorial(Point const& p) { typedef typename coordinate_type<Point>::type coord_type; typedef math::detail::constants_on_spheroid < coord_type, typename coordinate_system<Point>::type::units > constants; coord_type const pi_2 = constants::half_period() / 2; Point res = p; set<1>(res, pi_2 - get<1>(p)); return res; } }; // TODO: specialize collected_vector for geographic_tag #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace collect_vectors { template <typename Range, typename Collection> struct range_collect_vectors { typedef typename boost::range_value<Collection>::type item_type; typedef typename item_type::type calculation_type; static inline void apply(Collection& collection, Range const& range) { typedef geometry::detail::normalized_view < Range const > normalized_range_type; apply_impl(collection, normalized_range_type(range)); } private: template <typename NormalizedRange> static inline void apply_impl(Collection& collection, NormalizedRange const& range) { if (boost::size(range) < 2) { return; } typedef typename boost::range_size<Collection>::type collection_size_t; collection_size_t c_old_size = boost::size(collection); typedef typename boost::range_iterator<NormalizedRange const>::type iterator; bool is_first = true; iterator it = boost::begin(range); for (iterator prev = it++; it != boost::end(range); prev = it++) { typename boost::range_value<Collection>::type v(*prev, *it); // Normalize the vector -> this results in points+direction // and is comparible between geometries // Avoid non-duplicate points (AND division by zero) if (v.normalize()) { // Avoid non-direction changing points if (is_first || ! collection.back().next_is_collinear(v)) { collection.push_back(v); } is_first = false; } } // If first one has same direction as last one, remove first one collection_size_t collected_count = boost::size(collection) - c_old_size; if ( collected_count > 1 ) { typedef typename boost::range_iterator<Collection>::type c_iterator; c_iterator first = range::pos(collection, c_old_size); if (collection.back().next_is_collinear(*first) ) { //collection.erase(first); // O(1) instead of O(N) *first = collection.back(); collection.pop_back(); } } } }; // Default version (cartesian) template <typename Box, typename Collection, typename CSTag = typename cs_tag<Box>::type> struct box_collect_vectors { // Calculate on coordinate type, but if it is integer, // then use double typedef typename boost::range_value<Collection>::type item_type; typedef typename item_type::type calculation_type; static inline void apply(Collection& collection, Box const& box) { typename point_type<Box>::type lower_left, lower_right, upper_left, upper_right; geometry::detail::assign_box_corners(box, lower_left, lower_right, upper_left, upper_right); typedef typename boost::range_value<Collection>::type item; collection.push_back(item(get<0>(lower_left), get<1>(lower_left), 0, 1)); collection.push_back(item(get<0>(upper_left), get<1>(upper_left), 1, 0)); collection.push_back(item(get<0>(upper_right), get<1>(upper_right), 0, -1)); collection.push_back(item(get<0>(lower_right), get<1>(lower_right), -1, 0)); } }; // NOTE: This is not fully correct because Box in spherical and geographic // cordinate systems cannot be seen as Polygon template <typename Box, typename Collection> struct box_collect_vectors<Box, Collection, spherical_equatorial_tag> { static inline void apply(Collection& collection, Box const& box) { typename point_type<Box>::type lower_left, lower_right, upper_left, upper_right; geometry::detail::assign_box_corners(box, lower_left, lower_right, upper_left, upper_right); typedef typename boost::range_value<Collection>::type item; collection.push_back(item(lower_left, upper_left)); collection.push_back(item(upper_left, upper_right)); collection.push_back(item(upper_right, lower_right)); collection.push_back(item(lower_right, lower_left)); } }; template <typename Box, typename Collection> struct box_collect_vectors<Box, Collection, spherical_polar_tag> : box_collect_vectors<Box, Collection, spherical_equatorial_tag> {}; template <typename Box, typename Collection> struct box_collect_vectors<Box, Collection, geographic_tag> : box_collect_vectors<Box, Collection, spherical_equatorial_tag> {}; template <typename Polygon, typename Collection> struct polygon_collect_vectors { static inline void apply(Collection& collection, Polygon const& polygon) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef range_collect_vectors<ring_type, Collection> per_range; per_range::apply(collection, exterior_ring(polygon)); typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { per_range::apply(collection, *it); } } }; template <typename MultiGeometry, typename Collection, typename SinglePolicy> struct multi_collect_vectors { static inline void apply(Collection& collection, MultiGeometry const& multi) { for (typename boost::range_iterator<MultiGeometry const>::type it = boost::begin(multi); it != boost::end(multi); ++it) { SinglePolicy::apply(collection, *it); } } }; }} // namespace detail::collect_vectors #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Tag, typename Collection, typename Geometry > struct collect_vectors { static inline void apply(Collection&, Geometry const&) {} }; template <typename Collection, typename Box> struct collect_vectors<box_tag, Collection, Box> : detail::collect_vectors::box_collect_vectors<Box, Collection> {}; template <typename Collection, typename Ring> struct collect_vectors<ring_tag, Collection, Ring> : detail::collect_vectors::range_collect_vectors<Ring, Collection> {}; template <typename Collection, typename LineString> struct collect_vectors<linestring_tag, Collection, LineString> : detail::collect_vectors::range_collect_vectors<LineString, Collection> {}; template <typename Collection, typename Polygon> struct collect_vectors<polygon_tag, Collection, Polygon> : detail::collect_vectors::polygon_collect_vectors<Polygon, Collection> {}; template <typename Collection, typename MultiPolygon> struct collect_vectors<multi_polygon_tag, Collection, MultiPolygon> : detail::collect_vectors::multi_collect_vectors < MultiPolygon, Collection, detail::collect_vectors::polygon_collect_vectors < typename boost::range_value<MultiPolygon>::type, Collection > > {}; } // namespace dispatch #endif /*! \ingroup collect_vectors \tparam Collection Collection type, should be e.g. std::vector<> \tparam Geometry geometry type \param collection the collection of vectors \param geometry the geometry to make collect_vectors */ template <typename Collection, typename Geometry> inline void collect_vectors(Collection& collection, Geometry const& geometry) { concepts::check<Geometry const>(); dispatch::collect_vectors < typename tag<Geometry>::type, Collection, Geometry >::apply(collection, geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP detail/equals/interface.hpp 0000644 00000023143 15125631656 0011766 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2015, 2016, 2017, 2019. // Modifications copyright (c) 2014-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP #include <cstddef> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/relate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type, typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type, std::size_t DimensionCount = dimension<Geometry1>::type::value, bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value > struct equals: not_implemented<Tag1, Tag2> {}; // If reversal is needed, perform it template < typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, typename CastedTag1, typename CastedTag2, std::size_t DimensionCount > struct equals<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, DimensionCount, true> : equals<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, DimensionCount, false> { template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { return equals < Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, DimensionCount, false >::apply(g2, g1, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct equals { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return dispatch::equals < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return dispatch::equals < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct equals { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions < Geometry1 const, Geometry2 const >(); return resolve_strategy::equals ::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: static_visitor<bool> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) , m_strategy(strategy) {} template <typename Geometry1> inline bool operator()(Geometry1 const& geometry1) const { return equals<Geometry1, Geometry2> ::apply(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy ) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: static_visitor<bool> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) , m_strategy(strategy) {} template <typename Geometry2> inline bool operator()(Geometry2 const& geometry2) const { return equals<Geometry1, Geometry2> ::apply(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply( Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy ) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct equals< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> inline bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return equals<Geometry1, Geometry2> ::apply(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply( boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy ) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_check{are spatially equal} \details \details_check12{equals, is spatially equal}. Spatially equal means that the same point set is included. A box can therefore be spatially equal to a ring or a polygon, or a linestring can be spatially equal to a multi-linestring or a segment. This only works theoretically, not all combinations are implemented yet. \ingroup equals \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Equals} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{equals} \return \return_check2{are spatially equal} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/equals.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::equals < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief \brief_check{are spatially equal} \details \details_check12{equals, is spatially equal}. Spatially equal means that the same point set is included. A box can therefore be spatially equal to a ring or a polygon, or a linestring can be spatially equal to a multi-linestring or a segment. This only works theoretically, not all combinations are implemented yet. \ingroup equals \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{are spatially equal} \qbk{[include reference/algorithms/equals.qbk]} */ template <typename Geometry1, typename Geometry2> inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::equals<Geometry1, Geometry2> ::apply(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP detail/equals/point_point.hpp 0000644 00000003165 15125631656 0012372 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland // This file was modified by Oracle on 2013-2018. // Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace equals { /*! \brief Internal utility function to detect of points are disjoint \note To avoid circular references */ template <typename Point1, typename Point2, typename Strategy> inline bool equals_point_point(Point1 const& point1, Point2 const& point2, Strategy const& ) { return Strategy::apply(point1, point2); } }} // namespace detail::equals #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_POINT_POINT_HPP detail/within/multi_point.hpp 0000644 00000023275 15125631656 0012407 0 ustar 00 // Boost.Geometry // Copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP #include <algorithm> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/index/rtree.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/strategies/covered_by.hpp> #include <boost/geometry/strategies/disjoint.hpp> #include <boost/geometry/util/type_traits.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace within { struct multi_point_point { template <typename MultiPoint, typename Point, typename Strategy> static inline bool apply(MultiPoint const& multi_point, Point const& point, Strategy const& strategy) { typedef typename boost::range_const_iterator<MultiPoint>::type iterator; for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { if (! strategy.apply(*it, point)) { return false; } } // all points of MultiPoint inside Point return true; } }; // NOTE: currently the strategy is ignored, math::equals() is used inside geometry::less<> struct multi_point_multi_point { template <typename MultiPoint1, typename MultiPoint2, typename Strategy> static inline bool apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Strategy const& /*strategy*/) { typedef typename boost::range_value<MultiPoint2>::type point2_type; typedef typename Strategy::cs_tag cs_tag; typedef geometry::less<void, -1, cs_tag> less_type; less_type const less = less_type(); std::vector<point2_type> points2(boost::begin(multi_point2), boost::end(multi_point2)); std::sort(points2.begin(), points2.end(), less); bool result = false; typedef typename boost::range_const_iterator<MultiPoint1>::type iterator; for ( iterator it = boost::begin(multi_point1) ; it != boost::end(multi_point1) ; ++it ) { if (! std::binary_search(points2.begin(), points2.end(), *it, less)) { return false; } else { result = true; } } return result; } }; // TODO: the complexity could be lesser // the second geometry could be "prepared"/sorted // For Linear geometries partition could be used // For Areal geometries point_in_geometry() would have to call the winding // strategy differently, currently it linearly calls the strategy for each // segment. So the segments would have to be sorted in a way consistent with // the strategy and then the strategy called only for the segments in range. template <bool Within> struct multi_point_single_geometry { template <typename MultiPoint, typename LinearOrAreal, typename Strategy> static inline bool apply(MultiPoint const& multi_point, LinearOrAreal const& linear_or_areal, Strategy const& strategy) { //typedef typename boost::range_value<MultiPoint>::type point1_type; typedef typename point_type<LinearOrAreal>::type point2_type; typedef model::box<point2_type> box2_type; // Create envelope of geometry box2_type box; geometry::envelope(linear_or_areal, box, strategy.get_envelope_strategy()); geometry::detail::expand_by_epsilon(box); typedef typename Strategy::disjoint_point_box_strategy_type point_in_box_type; // Test each Point with envelope and then geometry if needed // If in the exterior, break bool result = false; typedef typename boost::range_const_iterator<MultiPoint>::type iterator; for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { int in_val = 0; // exterior of box and of geometry if (! point_in_box_type::apply(*it, box) || (in_val = point_in_geometry(*it, linear_or_areal, strategy)) < 0) { result = false; break; } // interior : interior/boundary if (Within ? in_val > 0 : in_val >= 0) { result = true; } } return result; } }; // TODO: same here, probably the complexity could be lesser template <bool Within> struct multi_point_multi_geometry { template <typename MultiPoint, typename LinearOrAreal, typename Strategy> static inline bool apply(MultiPoint const& multi_point, LinearOrAreal const& linear_or_areal, Strategy const& strategy) { typedef typename point_type<LinearOrAreal>::type point2_type; typedef model::box<point2_type> box2_type; static const bool is_linear = util::is_linear<LinearOrAreal>::value; typename Strategy::envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); // TODO: box pairs could be constructed on the fly, inside the rtree // Prepare range of envelopes and ids std::size_t count2 = boost::size(linear_or_areal); typedef std::pair<box2_type, std::size_t> box_pair_type; typedef std::vector<box_pair_type> box_pair_vector; box_pair_vector boxes(count2); for (std::size_t i = 0 ; i < count2 ; ++i) { geometry::envelope(linear_or_areal, boxes[i].first, envelope_strategy); geometry::detail::expand_by_epsilon(boxes[i].first); boxes[i].second = i; } // Create R-tree typedef strategy::index::services::from_strategy < Strategy > index_strategy_from; typedef index::parameters < index::rstar<4>, typename index_strategy_from::type > index_parameters_type; index::rtree<box_pair_type, index_parameters_type> rtree(boxes.begin(), boxes.end(), index_parameters_type(index::rstar<4>(), index_strategy_from::get(strategy))); // For each point find overlapping envelopes and test corresponding single geometries // If a point is in the exterior break bool result = false; typedef typename boost::range_const_iterator<MultiPoint>::type iterator; for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { // TODO: investigate the possibility of using satisfies // TODO: investigate the possibility of using iterative queries (optimization below) box_pair_vector inters_boxes; rtree.query(index::intersects(*it), std::back_inserter(inters_boxes)); bool found_interior = false; bool found_boundary = false; int boundaries = 0; typedef typename box_pair_vector::const_iterator box_iterator; for (box_iterator box_it = inters_boxes.begin() ; box_it != inters_boxes.end() ; ++box_it ) { int const in_val = point_in_geometry(*it, range::at(linear_or_areal, box_it->second), strategy); if (in_val > 0) { found_interior = true; } else if (in_val == 0) { ++boundaries; } // If the result was set previously (interior or // interior/boundary found) the only thing that needs to be // done for other points is to make sure they're not // overlapping the exterior no need to analyse boundaries. if (result && in_val >= 0) { break; } } if (boundaries > 0) { if (is_linear && boundaries % 2 == 0) { found_interior = true; } else { found_boundary = true; } } // exterior if (! found_interior && ! found_boundary) { result = false; break; } // interior : interior/boundary if (Within ? found_interior : (found_interior || found_boundary)) { result = true; } } return result; } }; }} // namespace detail::within #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP detail/within/point_in_geometry.hpp 0000644 00000032746 15125631656 0013601 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/concepts/within_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/relate.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace within { template <typename Point1, typename Point2, typename Strategy> inline bool equals_point_point(Point1 const& p1, Point2 const& p2, Strategy const& strategy) { return equals::equals_point_point(p1, p2, strategy.get_equals_point_point_strategy()); } // TODO: is this needed? inline int check_result_type(int result) { return result; } template <typename T> inline T check_result_type(T result) { BOOST_GEOMETRY_ASSERT(false); return result; } template <typename Point, typename Range, typename Strategy> inline int point_in_range(Point const& point, Range const& range, Strategy const& strategy) { boost::ignore_unused(strategy); typedef typename boost::range_iterator<Range const>::type iterator_type; typename Strategy::state_type state; iterator_type it = boost::begin(range); iterator_type end = boost::end(range); for ( iterator_type previous = it++ ; it != end ; ++previous, ++it ) { if ( ! strategy.apply(point, *previous, *it, state) ) { break; } } return check_result_type(strategy.result(state)); } template <typename Geometry, typename Point, typename Range> inline int point_in_range(Point const& point, Range const& range) { typedef typename strategy::point_in_geometry::services::default_strategy < Point, Geometry >::type strategy_type; return point_in_range(point, range, strategy_type()); } }} // namespace detail::within namespace detail_dispatch { namespace within { // checks the relation between a point P and geometry G // returns 1 if P is in the interior of G // returns 0 if P is on the boundry of G // returns -1 if P is in the exterior of G template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type> struct point_in_geometry : not_implemented<Tag> {}; template <typename Point2> struct point_in_geometry<Point2, point_tag> { template <typename Point1, typename Strategy> static inline int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy) { boost::ignore_unused(strategy); return strategy.apply(point1, point2) ? 1 : -1; } }; template <typename Segment> struct point_in_geometry<Segment, segment_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Segment const& segment, Strategy const& strategy) { boost::ignore_unused(strategy); typedef typename geometry::point_type<Segment>::type point_type; point_type p0, p1; // TODO: don't copy points detail::assign_point_from_index<0>(segment, p0); detail::assign_point_from_index<1>(segment, p1); typename Strategy::state_type state; strategy.apply(point, p0, p1, state); int r = detail::within::check_result_type(strategy.result(state)); if ( r != 0 ) return -1; // exterior // if the point is equal to the one of the terminal points if ( detail::within::equals_point_point(point, p0, strategy) || detail::within::equals_point_point(point, p1, strategy) ) return 0; // boundary else return 1; // interior } }; template <typename Linestring> struct point_in_geometry<Linestring, linestring_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Linestring const& linestring, Strategy const& strategy) { std::size_t count = boost::size(linestring); if ( count > 1 ) { if ( detail::within::point_in_range(point, linestring, strategy) != 0 ) return -1; // exterior // if the linestring doesn't have a boundary if (detail::within::equals_point_point(range::front(linestring), range::back(linestring), strategy)) return 1; // interior // else if the point is equal to the one of the terminal points else if (detail::within::equals_point_point(point, range::front(linestring), strategy) || detail::within::equals_point_point(point, range::back(linestring), strategy)) return 0; // boundary else return 1; // interior } // TODO: for now degenerated linestrings are ignored // throw an exception here? /*else if ( count == 1 ) { if ( detail::equals::equals_point_point(point, range::front(linestring)) ) return 1; }*/ return -1; // exterior } }; template <typename Ring> struct point_in_geometry<Ring, ring_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Ring const& ring, Strategy const& strategy) { if ( boost::size(ring) < core_detail::closure::minimum_ring_size < geometry::closure<Ring>::value >::value ) { return -1; } detail::normalized_view<Ring const> view(ring); return detail::within::point_in_range(point, view, strategy); } }; // Polygon: in exterior ring, and if so, not within interior ring(s) template <typename Polygon> struct point_in_geometry<Polygon, polygon_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Polygon const& polygon, Strategy const& strategy) { int const code = point_in_geometry < typename ring_type<Polygon>::type >::apply(point, exterior_ring(polygon), strategy); if (code == 1) { typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { int const interior_code = point_in_geometry < typename ring_type<Polygon>::type >::apply(point, *it, strategy); if (interior_code != -1) { // If 0, return 0 (touch) // If 1 (inside hole) return -1 (outside polygon) // If -1 (outside hole) check other holes if any return -interior_code; } } } return code; } }; template <typename Geometry> struct point_in_geometry<Geometry, multi_point_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { typedef typename boost::range_value<Geometry>::type point_type; typedef typename boost::range_const_iterator<Geometry>::type iterator; for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) { int pip = point_in_geometry<point_type>::apply(point, *it, strategy); //BOOST_GEOMETRY_ASSERT(pip != 0); if ( pip > 0 ) // inside return 1; } return -1; // outside } }; template <typename Geometry> struct point_in_geometry<Geometry, multi_linestring_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { int pip = -1; // outside typedef typename boost::range_value<Geometry>::type linestring_type; typedef typename boost::range_value<linestring_type>::type point_type; typedef typename boost::range_iterator<Geometry const>::type iterator; iterator it = boost::begin(geometry); for ( ; it != boost::end(geometry) ; ++it ) { pip = point_in_geometry<linestring_type>::apply(point, *it, strategy); // inside or on the boundary if ( pip >= 0 ) { ++it; break; } } // outside if ( pip < 0 ) return -1; // TODO: the following isn't needed for covered_by() unsigned boundaries = pip == 0 ? 1 : 0; for ( ; it != boost::end(geometry) ; ++it ) { if ( boost::size(*it) < 2 ) continue; point_type const& front = range::front(*it); point_type const& back = range::back(*it); // is closed_ring - no boundary if ( detail::within::equals_point_point(front, back, strategy) ) continue; // is point on boundary if ( detail::within::equals_point_point(point, front, strategy) || detail::within::equals_point_point(point, back, strategy) ) { ++boundaries; } } // if the number of boundaries is odd, the point is on the boundary return boundaries % 2 ? 0 : 1; } }; template <typename Geometry> struct point_in_geometry<Geometry, multi_polygon_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { // For invalid multipolygons //int res = -1; // outside typedef typename boost::range_value<Geometry>::type polygon_type; typedef typename boost::range_const_iterator<Geometry>::type iterator; for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it ) { int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy); // inside or on the boundary if ( pip >= 0 ) return pip; // For invalid multi-polygons //if ( 1 == pip ) // inside polygon // return 1; //else if ( res < pip ) // point must be inside at least one polygon // res = pip; } return -1; // for valid multipolygons //return res; // for invalid multipolygons } }; }} // namespace detail_dispatch::within namespace detail { namespace within { // 1 - in the interior // 0 - in the boundry // -1 - in the exterior template <typename Point, typename Geometry, typename Strategy> inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) { concepts::within::check<Point, Geometry, Strategy>(); return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy); } template <typename Point, typename Geometry> inline int point_in_geometry(Point const& point, Geometry const& geometry) { typedef typename strategy::point_in_geometry::services::default_strategy < Point, Geometry >::type strategy_type; return point_in_geometry(point, geometry, strategy_type()); } template <typename Point, typename Geometry, typename Strategy> inline bool within_point_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) { return point_in_geometry(point, geometry, strategy) > 0; } template <typename Point, typename Geometry> inline bool within_point_geometry(Point const& point, Geometry const& geometry) { return point_in_geometry(point, geometry) > 0; } template <typename Point, typename Geometry, typename Strategy> inline bool covered_by_point_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy) { return point_in_geometry(point, geometry, strategy) >= 0; } template <typename Point, typename Geometry> inline bool covered_by_point_geometry(Point const& point, Geometry const& geometry) { return point_in_geometry(point, geometry) >= 0; } }} // namespace detail::within #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP detail/within/implementation.hpp 0000644 00000022713 15125631656 0013065 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP #include <cstddef> #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/detail/within/interface.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/order_as_direction.hpp> #include <boost/geometry/algorithms/detail/within/multi_point.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> #include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <deque> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace within { struct use_point_in_geometry { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return detail::within::within_point_geometry(geometry1, geometry2, strategy); } }; struct use_relate { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename detail::de9im::static_mask_within_type < Geometry1, Geometry2 >::type within_mask; return geometry::relate(geometry1, geometry2, within_mask(), strategy); } }; }} // namespace detail::within #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point, typename Box> struct within<Point, Box, point_tag, box_tag> { template <typename Strategy> static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) { boost::ignore_unused(strategy); return strategy.apply(point, box); } }; template <typename Box1, typename Box2> struct within<Box1, Box2, box_tag, box_tag> { template <typename Strategy> static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) { assert_dimension_equal<Box1, Box2>(); boost::ignore_unused(strategy); return strategy.apply(box1, box2); } }; // P/P template <typename Point1, typename Point2> struct within<Point1, Point2, point_tag, point_tag> : public detail::within::use_point_in_geometry {}; template <typename Point, typename MultiPoint> struct within<Point, MultiPoint, point_tag, multi_point_tag> : public detail::within::use_point_in_geometry {}; template <typename MultiPoint, typename Point> struct within<MultiPoint, Point, multi_point_tag, point_tag> : public detail::within::multi_point_point {}; template <typename MultiPoint1, typename MultiPoint2> struct within<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag> : public detail::within::multi_point_multi_point {}; // P/L template <typename Point, typename Segment> struct within<Point, Segment, point_tag, segment_tag> : public detail::within::use_point_in_geometry {}; template <typename Point, typename Linestring> struct within<Point, Linestring, point_tag, linestring_tag> : public detail::within::use_point_in_geometry {}; template <typename Point, typename MultiLinestring> struct within<Point, MultiLinestring, point_tag, multi_linestring_tag> : public detail::within::use_point_in_geometry {}; template <typename MultiPoint, typename Segment> struct within<MultiPoint, Segment, multi_point_tag, segment_tag> : public detail::within::multi_point_single_geometry<true> {}; template <typename MultiPoint, typename Linestring> struct within<MultiPoint, Linestring, multi_point_tag, linestring_tag> : public detail::within::multi_point_single_geometry<true> {}; template <typename MultiPoint, typename MultiLinestring> struct within<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag> : public detail::within::multi_point_multi_geometry<true> {}; // P/A template <typename Point, typename Ring> struct within<Point, Ring, point_tag, ring_tag> : public detail::within::use_point_in_geometry {}; template <typename Point, typename Polygon> struct within<Point, Polygon, point_tag, polygon_tag> : public detail::within::use_point_in_geometry {}; template <typename Point, typename MultiPolygon> struct within<Point, MultiPolygon, point_tag, multi_polygon_tag> : public detail::within::use_point_in_geometry {}; template <typename MultiPoint, typename Ring> struct within<MultiPoint, Ring, multi_point_tag, ring_tag> : public detail::within::multi_point_single_geometry<true> {}; template <typename MultiPoint, typename Polygon> struct within<MultiPoint, Polygon, multi_point_tag, polygon_tag> : public detail::within::multi_point_single_geometry<true> {}; template <typename MultiPoint, typename MultiPolygon> struct within<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag> : public detail::within::multi_point_multi_geometry<true> {}; // L/L template <typename Linestring1, typename Linestring2> struct within<Linestring1, Linestring2, linestring_tag, linestring_tag> : public detail::within::use_relate {}; template <typename Linestring, typename MultiLinestring> struct within<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag> : public detail::within::use_relate {}; template <typename MultiLinestring, typename Linestring> struct within<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag> : public detail::within::use_relate {}; template <typename MultiLinestring1, typename MultiLinestring2> struct within<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag> : public detail::within::use_relate {}; // L/A template <typename Linestring, typename Ring> struct within<Linestring, Ring, linestring_tag, ring_tag> : public detail::within::use_relate {}; template <typename MultiLinestring, typename Ring> struct within<MultiLinestring, Ring, multi_linestring_tag, ring_tag> : public detail::within::use_relate {}; template <typename Linestring, typename Polygon> struct within<Linestring, Polygon, linestring_tag, polygon_tag> : public detail::within::use_relate {}; template <typename MultiLinestring, typename Polygon> struct within<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag> : public detail::within::use_relate {}; template <typename Linestring, typename MultiPolygon> struct within<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag> : public detail::within::use_relate {}; template <typename MultiLinestring, typename MultiPolygon> struct within<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag> : public detail::within::use_relate {}; // A/A template <typename Ring1, typename Ring2> struct within<Ring1, Ring2, ring_tag, ring_tag> : public detail::within::use_relate {}; template <typename Ring, typename Polygon> struct within<Ring, Polygon, ring_tag, polygon_tag> : public detail::within::use_relate {}; template <typename Polygon, typename Ring> struct within<Polygon, Ring, polygon_tag, ring_tag> : public detail::within::use_relate {}; template <typename Polygon1, typename Polygon2> struct within<Polygon1, Polygon2, polygon_tag, polygon_tag> : public detail::within::use_relate {}; template <typename Ring, typename MultiPolygon> struct within<Ring, MultiPolygon, ring_tag, multi_polygon_tag> : public detail::within::use_relate {}; template <typename MultiPolygon, typename Ring> struct within<MultiPolygon, Ring, multi_polygon_tag, ring_tag> : public detail::within::use_relate {}; template <typename Polygon, typename MultiPolygon> struct within<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag> : public detail::within::use_relate {}; template <typename MultiPolygon, typename Polygon> struct within<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag> : public detail::within::use_relate {}; template <typename MultiPolygon1, typename MultiPolygon2> struct within<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag> : public detail::within::use_relate {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #include <boost/geometry/index/rtree.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP detail/within/within_no_turns.hpp 0000644 00000021547 15125631656 0013275 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013. // Modifications copyright (c) 2013, Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail_dispatch { namespace within { // returns true if G1 is within G2 // this function should be called only if there are no intersection points // otherwise it may return invalid result // e.g. when non-first point of G1 is outside G2 or when some rings of G1 are the same as rings of G2 template <typename Geometry1, typename Geometry2, typename Tag1 = typename geometry::tag<Geometry1>::type, typename Tag2 = typename geometry::tag<Geometry2>::type> struct within_no_turns { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename geometry::point_type<Geometry1>::type point1_type; point1_type p; if ( !geometry::point_on_border(p, geometry1) ) return false; return detail::within::point_in_geometry(p, geometry2, strategy) >= 0; } }; template <typename Geometry1, typename Geometry2> struct within_no_turns<Geometry1, Geometry2, ring_tag, polygon_tag> { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; point1_type p; if ( !geometry::point_on_border(p, geometry1) ) return false; // check if one of ring points is outside the polygon if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 ) return false; // Now check if holes of G2 aren't inside G1 typedef typename boost::range_const_iterator < typename geometry::interior_type<Geometry2>::type >::type iterator; for ( iterator it = boost::begin(geometry::interior_rings(geometry2)) ; it != boost::end(geometry::interior_rings(geometry2)) ; ++it ) { point2_type p; if ( !geometry::point_on_border(p, *it) ) return false; if ( detail::within::point_in_geometry(p, geometry1, strategy) > 0 ) return false; } return true; } }; template <typename Geometry1, typename Geometry2> struct within_no_turns<Geometry1, Geometry2, polygon_tag, polygon_tag> { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; point1_type p; if ( !geometry::point_on_border(p, geometry1) ) return false; // check if one of ring points is outside the polygon if ( detail::within::point_in_geometry(p, geometry2, strategy) < 0 ) return false; // Now check if holes of G2 aren't inside G1 typedef typename boost::range_const_iterator < typename geometry::interior_type<Geometry2>::type >::type iterator2; for ( iterator2 it = boost::begin(geometry::interior_rings(geometry2)) ; it != boost::end(geometry::interior_rings(geometry2)) ; ++it ) { point2_type p2; if ( !geometry::point_on_border(p2, *it) ) return false; // if the hole of G2 is inside G1 if ( detail::within::point_in_geometry(p2, geometry1, strategy) > 0 ) { // if it's also inside one of the G1 holes, it's ok bool ok = false; typedef typename boost::range_const_iterator < typename geometry::interior_type<Geometry1>::type >::type iterator1; for ( iterator1 it1 = boost::begin(geometry::interior_rings(geometry1)) ; it1 != boost::end(geometry::interior_rings(geometry1)) ; ++it1 ) { if ( detail::within::point_in_geometry(p2, *it1, strategy) < 0 ) { ok = true; break; } } if ( !ok ) return false; } } return true; } }; template <typename Geometry1, typename Geometry2, typename Tag1 = typename geometry::tag<Geometry1>::type, typename Tag2 = typename geometry::tag<Geometry2>::type, bool IsMulti1 = boost::is_base_of<geometry::multi_tag, Tag1>::value, bool IsMulti2 = boost::is_base_of<geometry::multi_tag, Tag2>::value> struct within_no_turns_multi { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return within_no_turns<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } }; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, false> { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // All values of G1 must be inside G2 typedef typename boost::range_value<Geometry1>::type subgeometry1; typedef typename boost::range_const_iterator<Geometry1>::type iterator; for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) { if ( !within_no_turns<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) ) return false; } return true; } }; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, false, true> { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // G1 must be within at least one value of G2 typedef typename boost::range_value<Geometry2>::type subgeometry2; typedef typename boost::range_const_iterator<Geometry2>::type iterator; for ( iterator it = boost::begin(geometry2) ; it != boost::end(geometry2) ; ++it ) { if ( within_no_turns<Geometry1, subgeometry2>::apply(geometry1, *it, strategy) ) return true; } return false; } }; template <typename Geometry1, typename Geometry2, typename Tag1, typename Tag2> struct within_no_turns_multi<Geometry1, Geometry2, Tag1, Tag2, true, true> { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // each value of G1 must be inside at least one value of G2 typedef typename boost::range_value<Geometry1>::type subgeometry1; typedef typename boost::range_const_iterator<Geometry1>::type iterator; for ( iterator it = boost::begin(geometry1) ; it != boost::end(geometry1) ; ++it ) { if ( !within_no_turns_multi<subgeometry1, Geometry2>::apply(*it, geometry2, strategy) ) return false; } return true; } }; }} // namespace detail_dispatch::within namespace detail { namespace within { template <typename Geometry1, typename Geometry2, typename Strategy> inline bool within_no_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return detail_dispatch::within::within_no_turns_multi<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } }} // namespace detail::within #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_WITHIN_NO_TURNS_HPP detail/within/interface.hpp 0000644 00000021763 15125631656 0012004 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013, 2014, 2017, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP #include <boost/concept_check.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/concepts/within_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/within.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > struct within : not_implemented<Tag1, Tag2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct within { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::within::check<Geometry1, Geometry2, Strategy>(); return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::within::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct within { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); assert_dimension_equal<Geometry1, Geometry2>(); return resolve_strategy::within::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) , m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return within<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) , m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return within<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2 ); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct within< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy): m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return within<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } /*! \brief \brief_check12{is completely inside} \ingroup within \details \details_check12{within, is completely inside}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry which might be within the second geometry \param geometry2 \param_geometry which might contain the first geometry \return true if geometry1 is completely contained within geometry2, else false \note The default strategy is used for within detection \qbk{[include reference/algorithms/within.qbk]} \qbk{ [heading Example] [within] [within_output] } */ template<typename Geometry1, typename Geometry2> inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::within < Geometry1, Geometry2 >::apply(geometry1, geometry2, default_strategy()); } /*! \brief \brief_check12{is completely inside} \brief_strategy \ingroup within \details \details_check12{within, is completely inside}, \brief_strategy. \details_strategy_reasons \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry which might be within the second geometry \param geometry2 \param_geometry which might contain the first geometry \param strategy strategy to be used \return true if geometry1 is completely contained within geometry2, else false \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/within.qbk]} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_within_winding Winding (coordinate system agnostic)] \* [link geometry.reference.strategies.strategy_within_franklin Franklin (cartesian)] \* [link geometry.reference.strategies.strategy_within_crossings_multiply Crossings Multiply (cartesian)] [heading Example] [within_strategy] [within_strategy_output] } */ template<typename Geometry1, typename Geometry2, typename Strategy> inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::within < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP detail/counting.hpp 0000644 00000005457 15125631656 0010372 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP #include <cstddef> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace counting { template <std::size_t D> struct other_count { template <typename Geometry> static inline std::size_t apply(Geometry const&) { return D; } template <typename Geometry> static inline std::size_t apply(Geometry const&, bool) { return D; } }; template <typename RangeCount> struct polygon_count { template <typename Polygon> static inline std::size_t apply(Polygon const& poly) { std::size_t n = RangeCount::apply(exterior_ring(poly)); typename interior_return_type<Polygon const>::type rings = interior_rings(poly); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { n += RangeCount::apply(*it); } return n; } }; template <typename SingleCount> struct multi_count { template <typename MultiGeometry> static inline std::size_t apply(MultiGeometry const& geometry) { std::size_t n = 0; for (typename boost::range_iterator<MultiGeometry const>::type it = boost::begin(geometry); it != boost::end(geometry); ++it) { n += SingleCount::apply(*it); } return n; } }; }} // namespace detail::counting #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP detail/num_distinct_consecutive_points.hpp 0000644 00000005041 15125631656 0015234 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP #include <algorithm> #include <cstddef> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { // returns the number of distinct values in the range; // return values are 0u through MaximumNumber, where MaximumNumber // corresponds to MaximumNumber or more distinct values // // FUTURE: take into account topologically closed ranges; // add appropriate template parameter(s) to control whether // the closing point for topologically closed ranges is to be // accounted for separately or not template < typename Range, std::size_t MaximumNumber, bool AllowDuplicates /* true */, typename NotEqualTo > struct num_distinct_consecutive_points { static inline std::size_t apply(Range const& range) { typedef typename boost::range_iterator<Range const>::type iterator; std::size_t const size = boost::size(range); if ( size < 2u ) { return (size < MaximumNumber) ? size : MaximumNumber; } iterator current = boost::begin(range); std::size_t counter(0); do { ++counter; iterator next = std::find_if(current, boost::end(range), NotEqualTo(*current)); current = next; } while ( current != boost::end(range) && counter <= MaximumNumber ); return counter; } }; template <typename Range, std::size_t MaximumNumber, typename NotEqualTo> struct num_distinct_consecutive_points<Range, MaximumNumber, false, NotEqualTo> { static inline std::size_t apply(Range const& range) { std::size_t const size = boost::size(range); return (size < MaximumNumber) ? size : MaximumNumber; } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NUM_DISTINCT_CONSECUTIVE_POINTS_HPP detail/relation/implementation.hpp 0000644 00000001213 15125631656 0013370 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATION_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATION_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/relate/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATION_IMPLEMENTATION_HPP detail/relation/interface.hpp 0000644 00000015265 15125631656 0012317 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATION_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATION_INTERFACE_HPP #include <boost/geometry/algorithms/detail/relate/interface.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template <typename Geometry1, typename Geometry2> struct result_handler_type<Geometry1, Geometry2, geometry::de9im::matrix> { typedef matrix_handler<geometry::de9im::matrix> type; }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct relation { template <typename Matrix, typename Strategy> static inline Matrix apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); assert_dimension_equal<Geometry1, Geometry2>(); typename detail::relate::result_handler_type < Geometry1, Geometry2, Matrix >::type handler; resolve_strategy::relate::apply(geometry1, geometry2, handler, strategy); return handler.result(); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct relation<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Matrix, typename Strategy> struct visitor : boost::static_visitor<Matrix> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2), m_strategy(strategy) {} template <typename Geometry1> Matrix operator()(Geometry1 const& geometry1) const { return relation<Geometry1, Geometry2> ::template apply<Matrix>(geometry1, m_geometry2, m_strategy); } }; template <typename Matrix, typename Strategy> static inline Matrix apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Matrix, Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct relation<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Matrix, typename Strategy> struct visitor : boost::static_visitor<Matrix> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1), m_strategy(strategy) {} template <typename Geometry2> Matrix operator()(Geometry2 const& geometry2) const { return relation<Geometry1, Geometry2> ::template apply<Matrix>(m_geometry1, geometry2, m_strategy); } }; template <typename Matrix, typename Strategy> static inline Matrix apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Matrix, Strategy>(geometry1, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct relation < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Matrix, typename Strategy> struct visitor : boost::static_visitor<Matrix> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> Matrix operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return relation<Geometry1, Geometry2> ::template apply<Matrix>(geometry1, geometry2, m_strategy); } }; template <typename Matrix, typename Strategy> static inline Matrix apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Matrix, Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief Calculates the relation between a pair of geometries as defined in DE-9IM. \ingroup relation \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Relation} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{relation} \return The DE-9IM matrix expressing the relation between geometries. \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/relation.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline de9im::matrix relation(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::relation < Geometry1, Geometry2 >::template apply<de9im::matrix>(geometry1, geometry2, strategy); } /*! \brief Calculates the relation between a pair of geometries as defined in DE-9IM. \ingroup relation \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return The DE-9IM matrix expressing the relation between geometries. \qbk{[include reference/algorithms/relation.qbk]} */ template <typename Geometry1, typename Geometry2> inline de9im::matrix relation(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::relation < Geometry1, Geometry2 >::template apply<de9im::matrix>(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_INTERFACE_HPP detail/extreme_points.hpp 0000644 00000046641 15125631656 0011611 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2013 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2013 Bruno Lalande, Paris, France. // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP #include <cstddef> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/strategies/side.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace extreme_points { template <std::size_t Dimension> struct compare { template <typename Point> inline bool operator()(Point const& lhs, Point const& rhs) { return geometry::get<Dimension>(lhs) < geometry::get<Dimension>(rhs); } }; template <std::size_t Dimension, typename PointType, typename CoordinateType> inline void move_along_vector(PointType& point, PointType const& extreme, CoordinateType const& base_value) { // Moves a point along the vector (point, extreme) in the direction of the extreme point // This adapts the possibly uneven legs of the triangle (or trapezium-like shape) // _____extreme _____ // / \ / \ . // /base \ => / \ point . // \ point . // // For so-called intruders, it can be used to adapt both legs to the level of "base" // For the base, it can be used to adapt both legs to the level of the max-value of the intruders // If there are 2 or more extreme values, use the one close to 'point' to have a correct vector CoordinateType const value = geometry::get<Dimension>(point); //if (geometry::math::equals(value, base_value)) if (value >= base_value) { return; } PointType vector = point; subtract_point(vector, extreme); CoordinateType const diff = geometry::get<Dimension>(vector); // diff should never be zero // because of the way our triangle/trapezium is build. // We just return if it would be the case. if (geometry::math::equals(diff, 0)) { return; } CoordinateType const base_diff = base_value - geometry::get<Dimension>(extreme); multiply_value(vector, base_diff); divide_value(vector, diff); // The real move: point = extreme; add_point(point, vector); } template <std::size_t Dimension, typename Range, typename CoordinateType> inline void move_along_vector(Range& range, CoordinateType const& base_value) { if (range.size() >= 3) { move_along_vector<Dimension>(range.front(), *(range.begin() + 1), base_value); move_along_vector<Dimension>(range.back(), *(range.rbegin() + 1), base_value); } } template<typename Ring, std::size_t Dimension> struct extreme_points_on_ring { typedef typename geometry::coordinate_type<Ring>::type coordinate_type; typedef typename boost::range_iterator<Ring const>::type range_iterator; typedef typename geometry::point_type<Ring>::type point_type; template <typename CirclingIterator, typename Points> static inline bool extend(CirclingIterator& it, std::size_t n, coordinate_type max_coordinate_value, Points& points, int direction) { std::size_t safe_index = 0; do { it += direction; points.push_back(*it); if (safe_index++ >= n) { // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop) return false; } } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value)); return true; } // Overload without adding to poinst template <typename CirclingIterator> static inline bool extend(CirclingIterator& it, std::size_t n, coordinate_type max_coordinate_value, int direction) { std::size_t safe_index = 0; do { it += direction; if (safe_index++ >= n) { // E.g.: ring is completely horizontal or vertical (= invalid, but we don't want to have an infinite loop) return false; } } while (geometry::math::equals(geometry::get<Dimension>(*it), max_coordinate_value)); return true; } template <typename CirclingIterator> static inline bool extent_both_sides(Ring const& ring, point_type extreme, CirclingIterator& left, CirclingIterator& right) { std::size_t const n = boost::size(ring); coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme); if (! extend(left, n, max_coordinate_value, -1)) { return false; } if (! extend(right, n, max_coordinate_value, +1)) { return false; } return true; } template <typename Collection, typename CirclingIterator> static inline bool collect(Ring const& ring, point_type extreme, Collection& points, CirclingIterator& left, CirclingIterator& right) { std::size_t const n = boost::size(ring); coordinate_type const max_coordinate_value = geometry::get<Dimension>(extreme); // Collects first left, which is reversed (if more than one point) then adds the top itself, then right if (! extend(left, n, max_coordinate_value, points, -1)) { return false; } std::reverse(points.begin(), points.end()); points.push_back(extreme); if (! extend(right, n, max_coordinate_value, points, +1)) { return false; } return true; } template <typename Extremes, typename Intruders, typename CirclingIterator, typename SideStrategy> static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right, Extremes const& extremes, Intruders& intruders, SideStrategy const& strategy) { if (boost::size(extremes) < 3) { return; } coordinate_type const min_value = geometry::get<Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<Dimension>())); // Also select left/right (if Dimension=1) coordinate_type const other_min = geometry::get<1 - Dimension>(*std::min_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>())); coordinate_type const other_max = geometry::get<1 - Dimension>(*std::max_element(boost::begin(extremes), boost::end(extremes), compare<1 - Dimension>())); std::size_t defensive_check_index = 0; // in case we skip over left/right check, collect modifies right too std::size_t const n = boost::size(ring); while (left != right && defensive_check_index < n) { coordinate_type const coordinate = geometry::get<Dimension>(*right); coordinate_type const other_coordinate = geometry::get<1 - Dimension>(*right); if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max) { int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1; int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor; int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor; // If not lying left from any of the extemes side if (first_side != 1 && last_side != 1) { //std::cout << "first " << first_side << " last " << last_side << std::endl; // we start at this intrusion until it is handled, and don't affect our initial left iterator CirclingIterator left_intrusion_it = right; typename boost::range_value<Intruders>::type intruder; collect(ring, *right, intruder, left_intrusion_it, right); // Also moves these to base-level, makes sorting possible which can be done in case of self-tangencies // (we might postpone this action, it is often not necessary. However it is not time-consuming) move_along_vector<Dimension>(intruder, min_value); intruders.push_back(intruder); --right; } } ++right; defensive_check_index++; } } template <typename Extremes, typename Intruders, typename SideStrategy> static inline void get_intruders(Ring const& ring, Extremes const& extremes, Intruders& intruders, SideStrategy const& strategy) { std::size_t const n = boost::size(ring); if (n >= 3) { geometry::ever_circling_range_iterator<Ring const> left(ring); geometry::ever_circling_range_iterator<Ring const> right(ring); ++right; get_intruders(ring, left, right, extremes, intruders, strategy); } } template <typename Iterator, typename SideStrategy> static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy) { typename std::iterator_traits<Iterator>::difference_type const index = std::distance(boost::begin(ring), it); geometry::ever_circling_range_iterator<Ring const> left(ring); geometry::ever_circling_range_iterator<Ring const> right(ring); left += index; right += index; if (! extent_both_sides(ring, *it, left, right)) { return false; } int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1; int const first_side = strategy.apply(*(right - 1), *right, *left) * factor; int const last_side = strategy.apply(*left, *(left + 1), *right) * factor; //std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl; // Turn should not be left (actually, it should be right because extent removes horizontal/collinear cases) return first_side != 1 && last_side != 1; } // Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring template <typename Extremes, typename Intruders, typename SideStrategy> static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders, SideStrategy const& strategy) { std::size_t const n = boost::size(ring); if (n < 3) { return false; } // Get all maxima, usually one. In case of self-tangencies, or self-crossings, // the max might be is not valid. A valid max should make a right turn range_iterator max_it = boost::begin(ring); compare<Dimension> smaller; for (range_iterator it = max_it + 1; it != boost::end(ring); ++it) { if (smaller(*max_it, *it) && right_turn(ring, it, strategy)) { max_it = it; } } if (max_it == boost::end(ring)) { return false; } typename std::iterator_traits<range_iterator>::difference_type const index = std::distance(boost::begin(ring), max_it); //std::cout << "Extreme point lies at " << index << " having " << geometry::wkt(*max_it) << std::endl; geometry::ever_circling_range_iterator<Ring const> left(ring); geometry::ever_circling_range_iterator<Ring const> right(ring); left += index; right += index; // Collect all points (often 3) in a temporary vector std::vector<point_type> points; points.reserve(3); if (! collect(ring, *max_it, points, left, right)) { return false; } //std::cout << "Built vector of " << points.size() << std::endl; coordinate_type const front_value = geometry::get<Dimension>(points.front()); coordinate_type const back_value = geometry::get<Dimension>(points.back()); coordinate_type const base_value = (std::max)(front_value, back_value); if (front_value < back_value) { move_along_vector<Dimension>(points.front(), *(points.begin() + 1), base_value); } else { move_along_vector<Dimension>(points.back(), *(points.rbegin() + 1), base_value); } std::copy(points.begin(), points.end(), std::back_inserter(extremes)); get_intruders(ring, left, right, extremes, intruders, strategy); return true; } }; }} // namespace detail::extreme_points #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, std::size_t Dimension, typename GeometryTag = typename tag<Geometry>::type > struct extreme_points {}; template<typename Ring, std::size_t Dimension> struct extreme_points<Ring, Dimension, ring_tag> : detail::extreme_points::extreme_points_on_ring<Ring, Dimension> {}; template<typename Polygon, std::size_t Dimension> struct extreme_points<Polygon, Dimension, polygon_tag> { template <typename Extremes, typename Intruders, typename SideStrategy> static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders, SideStrategy const& strategy) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef detail::extreme_points::extreme_points_on_ring < ring_type, Dimension > ring_implementation; if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders, strategy)) { return false; } // For a polygon, its interior rings can contain intruders typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { ring_implementation::get_intruders(*it, extremes, intruders, strategy); } return true; } }; template<typename Box> struct extreme_points<Box, 1, box_tag> { template <typename Extremes, typename Intruders, typename SideStrategy> static inline bool apply(Box const& box, Extremes& extremes, Intruders& , SideStrategy const& ) { extremes.resize(4); geometry::detail::assign_box_corners_oriented<false>(box, extremes); // ll,ul,ur,lr, contains too exactly the right info return true; } }; template<typename Box> struct extreme_points<Box, 0, box_tag> { template <typename Extremes, typename Intruders, typename SideStrategy> static inline bool apply(Box const& box, Extremes& extremes, Intruders& , SideStrategy const& ) { extremes.resize(4); geometry::detail::assign_box_corners_oriented<false>(box, extremes); // ll,ul,ur,lr, rotate one to start with UL and end with LL std::rotate(extremes.begin(), extremes.begin() + 1, extremes.end()); return true; } }; template<typename MultiPolygon, std::size_t Dimension> struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag> { template <typename Extremes, typename Intruders, typename SideStrategy> static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders, SideStrategy const& strategy) { // Get one for the very first polygon, that is (for the moment) enough. // It is not guaranteed the "extreme" then, but for the current purpose // (point_on_surface) it can just be this point. if (boost::size(multi) >= 1) { return extreme_points < typename boost::range_value<MultiPolygon const>::type, Dimension, polygon_tag >::apply(*boost::begin(multi), extremes, intruders, strategy); } return false; } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief Returns extreme points (for Edge=1 in dimension 1, so the top, for Edge=0 in dimension 0, the right side) \note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that. */ template < std::size_t Edge, typename Geometry, typename Extremes, typename Intruders, typename SideStrategy > inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders, SideStrategy const& strategy) { concepts::check<Geometry const>(); // Extremes is not required to follow a geometry concept (but it should support an output iterator), // but its elements should fulfil the point-concept concepts::check<typename boost::range_value<Extremes>::type>(); // Intruders should contain collections which value type is point-concept // Extremes might be anything (supporting an output iterator), but its elements should fulfil the point-concept concepts::check < typename boost::range_value < typename boost::range_value<Intruders>::type >::type const >(); return dispatch::extreme_points < Geometry, Edge >::apply(geometry, extremes, intruders, strategy); } template < std::size_t Edge, typename Geometry, typename Extremes, typename Intruders > inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders) { typedef typename strategy::side::services::default_strategy < typename cs_tag<Geometry>::type >::type strategy_type; return geometry::extreme_points<Edge>(geometry,extremes, intruders, strategy_type()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXTREME_POINTS_HPP detail/sweep.hpp 0000644 00000004046 15125631656 0007660 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SWEEP_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SWEEP_HPP #include <boost/core/ignore_unused.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace sweep { struct no_interrupt_policy { static bool const enabled = false; template <typename Event> static inline bool apply(Event const&) { return false; } }; }} // namespace detail::sweep #endif // DOXYGEN_NO_DETAIL template < typename Range, typename PriorityQueue, typename InitializationVisitor, typename EventVisitor, typename InterruptPolicy > inline void sweep(Range const& range, PriorityQueue& queue, InitializationVisitor& initialization_visitor, EventVisitor& event_visitor, InterruptPolicy const& interrupt_policy) { typedef typename PriorityQueue::value_type event_type; initialization_visitor.apply(range, queue, event_visitor); while (! queue.empty()) { event_type event = queue.top(); queue.pop(); event_visitor.apply(event, queue); if (interrupt_policy.enabled && interrupt_policy.apply(event)) { break; } } boost::ignore_unused(interrupt_policy); } template < typename Range, typename PriorityQueue, typename InitializationVisitor, typename EventVisitor > inline void sweep(Range const& range, PriorityQueue& queue, InitializationVisitor& initialization_visitor, EventVisitor& event_visitor) { sweep(range, queue, initialization_visitor, event_visitor, detail::sweep::no_interrupt_policy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SWEEP_HPP detail/interior_iterator.hpp 0000644 00000003350 15125631656 0012276 0 ustar 00 // Boost.Geometry // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP #include <boost/range/iterator.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/interior_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { /*! \brief Structure defining the type of interior rings iterator \note If the Geometry is const, const iterator is defined. \tparam Geometry \tparam_geometry */ template <typename Geometry> struct interior_iterator { typedef typename boost::range_iterator < typename geometry::interior_type<Geometry>::type >::type type; }; template <typename BaseT, typename T> struct copy_const { typedef T type; }; template <typename BaseT, typename T> struct copy_const<BaseT const, T> { typedef T const type; }; template <typename Geometry> struct interior_ring_iterator { typedef typename boost::range_iterator < typename copy_const < typename geometry::interior_type<Geometry>::type, typename boost::range_value < typename geometry::interior_type<Geometry>::type >::type >::type >::type type; }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERIOR_ITERATOR_HPP detail/recalculate.hpp 0000644 00000015520 15125631656 0011020 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2013 Bruno Lalande, Paris, France. // Copyright (c) 2013 Mateusz Loskot, London, UK. // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP #include <cstddef> #include <boost/concept/requires.hpp> #include <boost/concept_check.hpp> #include <boost/numeric/conversion/bounds.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace recalculate { template <std::size_t Dimension> struct recalculate_point { template <typename Point1, typename Point2, typename Strategy> static inline void apply(Point1& point1, Point2 const& point2, Strategy const& strategy) { std::size_t const dim = Dimension - 1; geometry::set<dim>(point1, strategy.template apply<dim>(geometry::get<dim>(point2))); recalculate_point<dim>::apply(point1, point2, strategy); } }; template <> struct recalculate_point<0> { template <typename Point1, typename Point2, typename Strategy> static inline void apply(Point1&, Point2 const&, Strategy const&) { } }; template <std::size_t Dimension> struct recalculate_indexed { template <typename Geometry1, typename Geometry2, typename Strategy> static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // Do it for both indices in one dimension static std::size_t const dim = Dimension - 1; geometry::set<0, dim>(geometry1, strategy.template apply<dim>(geometry::get<0, dim>(geometry2))); geometry::set<1, dim>(geometry1, strategy.template apply<dim>(geometry::get<1, dim>(geometry2))); recalculate_indexed<dim>::apply(geometry1, geometry2, strategy); } }; template <> struct recalculate_indexed<0> { template <typename Geometry1, typename Geometry2, typename Strategy> static inline void apply(Geometry1& , Geometry2 const& , Strategy const& ) { } }; struct range_to_range { template < typename Range1, typename Range2, typename Strategy > static inline void apply(Range1& destination, Range2 const& source, Strategy const& strategy) { typedef typename geometry::point_type<Range2>::type point_type; typedef recalculate_point<geometry::dimension<point_type>::value> per_point; geometry::clear(destination); for (typename boost::range_iterator<Range2 const>::type it = boost::begin(source); it != boost::end(source); ++it) { point_type p; per_point::apply(p, *it, strategy); geometry::append(destination, p); } } }; struct polygon_to_polygon { private: template < typename IteratorIn, typename IteratorOut, typename Strategy > static inline void iterate(IteratorIn begin, IteratorIn end, IteratorOut it_out, Strategy const& strategy) { for (IteratorIn it_in = begin; it_in != end; ++it_in, ++it_out) { range_to_range::apply(*it_out, *it_in, strategy); } } template < typename InteriorRingsOut, typename InteriorRingsIn, typename Strategy > static inline void apply_interior_rings( InteriorRingsOut& interior_rings_out, InteriorRingsIn const& interior_rings_in, Strategy const& strategy) { traits::resize<InteriorRingsOut>::apply(interior_rings_out, boost::size(interior_rings_in)); iterate( boost::begin(interior_rings_in), boost::end(interior_rings_in), boost::begin(interior_rings_out), strategy); } public: template < typename Polygon1, typename Polygon2, typename Strategy > static inline void apply(Polygon1& destination, Polygon2 const& source, Strategy const& strategy) { range_to_range::apply(geometry::exterior_ring(destination), geometry::exterior_ring(source), strategy); apply_interior_rings(geometry::interior_rings(destination), geometry::interior_rings(source), strategy); } }; }} // namespace detail::recalculate #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename geometry::tag<Geometry1>::type, typename Tag2 = typename geometry::tag<Geometry2>::type > struct recalculate : not_implemented<Tag1, Tag2> {}; template <typename Point1, typename Point2> struct recalculate<Point1, Point2, point_tag, point_tag> : detail::recalculate::recalculate_point<geometry::dimension<Point1>::value> {}; template <typename Box1, typename Box2> struct recalculate<Box1, Box2, box_tag, box_tag> : detail::recalculate::recalculate_indexed<geometry::dimension<Box1>::value> {}; template <typename Segment1, typename Segment2> struct recalculate<Segment1, Segment2, segment_tag, segment_tag> : detail::recalculate::recalculate_indexed<geometry::dimension<Segment1>::value> {}; template <typename Polygon1, typename Polygon2> struct recalculate<Polygon1, Polygon2, polygon_tag, polygon_tag> : detail::recalculate::polygon_to_polygon {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH template <typename Geometry1, typename Geometry2, typename Strategy> inline void recalculate(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1>(); concepts::check<Geometry2 const>(); // static assert dimensions (/types) are the same dispatch::recalculate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RECALCULATE_HPP detail/envelope/areal.hpp 0000644 00000004513 15125631656 0011435 0 ustar 00 // Boost.Geometry // Copyright (c) 2018 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/iterators/segment_iterator.hpp> #include <boost/geometry/algorithms/detail/envelope/range.hpp> #include <boost/geometry/algorithms/detail/envelope/linear.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { struct envelope_polygon { template <typename Polygon, typename Box, typename Strategy> static inline void apply(Polygon const& polygon, Box& mbr, Strategy const& strategy) { typename ring_return_type<Polygon const>::type ext_ring = exterior_ring(polygon); if (geometry::is_empty(ext_ring)) { // if the exterior ring is empty, consider the interior rings envelope_multi_range < envelope_range >::apply(interior_rings(polygon), mbr, strategy); } else { // otherwise, consider only the exterior ring envelope_range::apply(ext_ring, mbr, strategy); } } }; }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Ring> struct envelope<Ring, ring_tag> : detail::envelope::envelope_range {}; template <typename Polygon> struct envelope<Polygon, polygon_tag> : detail::envelope::envelope_polygon {}; template <typename MultiPolygon> struct envelope<MultiPolygon, multi_polygon_tag> : detail::envelope::envelope_multi_range < detail::envelope::envelope_polygon > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP detail/envelope/linear.hpp 0000644 00000003102 15125631656 0011614 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/envelope/range.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linestring> struct envelope<Linestring, linestring_tag> : detail::envelope::envelope_range {}; template <typename MultiLinestring> struct envelope<MultiLinestring, multi_linestring_tag> : detail::envelope::envelope_multi_range < detail::envelope::envelope_range > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP detail/envelope/range.hpp 0000644 00000010355 15125631656 0011446 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_HPP #include <iterator> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/detail/envelope/initialize.hpp> #include <boost/geometry/algorithms/detail/expand/box.hpp> #include <boost/geometry/algorithms/detail/expand/point.hpp> #include <boost/geometry/algorithms/detail/expand/segment.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { // implementation for simple ranges struct envelope_range { template <typename Iterator, typename Box, typename Strategy> static inline void apply(Iterator it, Iterator last, Box& mbr, Strategy const& strategy) { typedef typename std::iterator_traits<Iterator>::value_type value_type; // initialize MBR initialize<Box, 0, dimension<Box>::value>::apply(mbr); if (it != last) { // initialize box with first element in range dispatch::envelope < value_type >::apply(*it, mbr, strategy); // consider now the remaining elements in the range (if any) for (++it; it != last; ++it) { dispatch::expand < Box, value_type >::apply(mbr, *it, strategy); } } } template <typename Range, typename Box, typename Strategy> static inline void apply(Range const& range, Box& mbr, Strategy const& strategy) { using strategy_t = decltype(strategy.envelope(range, mbr)); return apply(strategy_t::begin(range), strategy_t::end(range), mbr, strategy); } }; // implementation for multi-ranges template <typename EnvelopePolicy> struct envelope_multi_range { template <typename MultiRange, typename Box, typename Strategy> static inline void apply(MultiRange const& multirange, Box& mbr, Strategy const& strategy) { using range_t = typename boost::range_value<MultiRange>::type; using strategy_t = decltype(strategy.envelope(std::declval<range_t>(), mbr)); using state_t = typename strategy_t::template multi_state<Box>; apply<state_t>(boost::begin(multirange), boost::end(multirange), mbr, strategy); } private: template <typename State, typename Iter, typename Box, typename Strategy> static inline void apply(Iter it, Iter last, Box& mbr, Strategy const& strategy) { State state; for (; it != last; ++it) { if (! geometry::is_empty(*it)) { Box helper_mbr; EnvelopePolicy::apply(*it, helper_mbr, strategy); state.apply(helper_mbr); } } state.result(mbr); } }; }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_HPP detail/envelope/intersects_antimeridian.hpp 0000644 00000004605 15125631656 0015262 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/algorithms/detail/normalize.hpp> namespace boost { namespace geometry { namespace detail { namespace envelope { struct intersects_antimeridian { template <typename Units, typename CoordinateType> static inline bool apply(CoordinateType const& lon1, CoordinateType const& lat1, CoordinateType const& lon2, CoordinateType const& lat2) { typedef math::detail::constants_on_spheroid < CoordinateType, Units > constants; return math::equals(math::abs(lat1), constants::max_latitude()) || math::equals(math::abs(lat2), constants::max_latitude()) || math::larger(math::abs(lon1 - lon2), constants::half_period()); } template <typename Segment> static inline bool apply(Segment const& segment) { return apply(detail::indexed_point_view<Segment, 0>(segment), detail::indexed_point_view<Segment, 1>(segment)); } template <typename Point> static inline bool apply(Point const& p1, Point const& p2) { Point p1_normalized = detail::return_normalized<Point>(p1); Point p2_normalized = detail::return_normalized<Point>(p2); return apply < typename coordinate_system<Point>::type::units >(geometry::get<0>(p1_normalized), geometry::get<1>(p1_normalized), geometry::get<0>(p2_normalized), geometry::get<1>(p2_normalized)); } }; }} // namespace detail::envelope }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP detail/envelope/transform_units.hpp 0000644 00000005603 15125631656 0013607 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_TRANSFORM_UNITS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_TRANSFORM_UNITS_HPP #include <cstddef> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/strategy_transform.hpp> #include <boost/geometry/views/detail/indexed_point_view.hpp> #include <boost/geometry/views/detail/two_dimensional_view.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/transform.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { template < typename GeometryIn, typename GeometryOut, typename TagIn = typename tag<GeometryIn>::type, typename TagOut = typename tag<GeometryOut>::type > struct transform_units_impl : not_implemented<TagIn, TagOut> {}; template <typename PointIn, typename PointOut> struct transform_units_impl<PointIn, PointOut, point_tag, point_tag> { static inline void apply(PointIn const& point_in, PointOut& point_out) { detail::two_dimensional_view<PointIn const> view_in(point_in); detail::two_dimensional_view<PointOut> view_out(point_out); geometry::transform(view_in, view_out); } }; template <typename BoxIn, typename BoxOut> struct transform_units_impl<BoxIn, BoxOut, box_tag, box_tag> { template <std::size_t Index> static inline void apply(BoxIn const& box_in, BoxOut& box_out) { typedef detail::indexed_point_view<BoxIn const, Index> view_in_type; typedef detail::indexed_point_view<BoxOut, Index> view_out_type; view_in_type view_in(box_in); view_out_type view_out(box_out); transform_units_impl < view_in_type, view_out_type >::apply(view_in, view_out); } static inline void apply(BoxIn const& box_in, BoxOut& box_out) { apply<min_corner>(box_in, box_out); apply<max_corner>(box_in, box_out); } }; // Short utility to transform the units of the first two coordinates of // geometry_in to the units of geometry_out template <typename GeometryIn, typename GeometryOut> inline void transform_units(GeometryIn const& geometry_in, GeometryOut& geometry_out) { transform_units_impl < GeometryIn, GeometryOut >::apply(geometry_in, geometry_out); } }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL }} // namespace boost:geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_TRANSFORM_UNITS_HPP detail/envelope/multipoint.hpp 0000644 00000002566 15125631656 0012563 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename MultiPoint> struct envelope<MultiPoint, multi_point_tag> { template <typename Box, typename Strategy> static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy) { // strategy.envelope(multipoint, mbr).apply(multipoint, mbr); using strategy_t = decltype(strategy.envelope(multipoint, mbr)); strategy_t::apply(multipoint, mbr); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP detail/envelope/implementation.hpp 0000644 00000003307 15125631656 0013376 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015, 2016. // Modifications copyright (c) 2015-2016, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/detail/envelope/areal.hpp> #include <boost/geometry/algorithms/detail/envelope/box.hpp> #include <boost/geometry/algorithms/detail/envelope/linear.hpp> #include <boost/geometry/algorithms/detail/envelope/multipoint.hpp> #include <boost/geometry/algorithms/detail/envelope/point.hpp> #include <boost/geometry/algorithms/detail/envelope/range.hpp> #include <boost/geometry/algorithms/detail/envelope/segment.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP detail/envelope/initialize.hpp 0000644 00000004444 15125631656 0012515 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP #include <cstddef> #include <boost/numeric/conversion/bounds.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/coordinate_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { template <std::size_t Dimension, std::size_t DimensionCount> struct initialize_loop { template <typename Box, typename CoordinateType> static inline void apply(Box& box, CoordinateType min_value, CoordinateType max_value) { geometry::set<min_corner, Dimension>(box, min_value); geometry::set<max_corner, Dimension>(box, max_value); initialize_loop < Dimension + 1, DimensionCount >::apply(box, min_value, max_value); } }; template <std::size_t DimensionCount> struct initialize_loop<DimensionCount, DimensionCount> { template <typename Box, typename CoordinateType> static inline void apply(Box&, CoordinateType, CoordinateType) { } }; template < typename Box, std::size_t Dimension = 0, std::size_t DimensionCount = dimension<Box>::value > struct initialize { typedef typename coordinate_type<Box>::type coordinate_type; static inline void apply(Box& box, coordinate_type min_value = boost::numeric::bounds<coordinate_type>::highest(), coordinate_type max_value = boost::numeric::bounds<coordinate_type>::lowest()) { initialize_loop < Dimension, DimensionCount >::apply(box, min_value, max_value); } }; }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP detail/envelope/box.hpp 0000644 00000002707 15125631656 0011144 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Box> struct envelope<Box, box_tag> { template<typename BoxIn, typename BoxOut, typename Strategy> static inline void apply(BoxIn const& box_in, BoxOut& mbr, Strategy const& strategy) { using strategy_t = decltype(strategy.envelope(box_in, mbr)); strategy_t::apply(box_in, mbr); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP detail/envelope/range_of_boxes.hpp 0000644 00000026760 15125631656 0013341 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_OF_BOXES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_OF_BOXES_HPP #include <algorithm> #include <cstddef> #include <type_traits> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/algorithms/detail/max_interval_gap.hpp> #include <boost/geometry/algorithms/detail/expand/indexed.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/detail/indexed_point_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { template <typename T> class longitude_interval { typedef T const& reference_type; public: typedef T value_type; typedef T difference_type; longitude_interval(T const& left, T const& right) { m_end[0] = left; m_end[1] = right; } template <std::size_t Index> reference_type get() const { return m_end[Index]; } difference_type length() const { return get<1>() - get<0>(); } private: T m_end[2]; }; template <typename Units> struct envelope_range_of_longitudes { template <std::size_t Index> struct longitude_less { template <typename Interval> inline bool operator()(Interval const& i1, Interval const& i2) const { return math::smaller(i1.template get<Index>(), i2.template get<Index>()); } }; template <typename RangeOfLongitudeIntervals, typename Longitude> static inline void apply(RangeOfLongitudeIntervals const& range, Longitude& lon_min, Longitude& lon_max) { typedef typename math::detail::constants_on_spheroid < Longitude, Units > constants; Longitude const zero = 0; Longitude const period = constants::period(); lon_min = lon_max = zero; // the range of longitude intervals can be empty if all input boxes // degenerate to the north or south pole (or combination of the two) // in this case the initialization values for lon_min and // lon_max are valid choices if (! boost::empty(range)) { lon_min = std::min_element(boost::begin(range), boost::end(range), longitude_less<0>())->template get<0>(); lon_max = std::max_element(boost::begin(range), boost::end(range), longitude_less<1>())->template get<1>(); if (math::larger(lon_max - lon_min, constants::half_period())) { Longitude max_gap_left, max_gap_right; Longitude max_gap = geometry::maximum_gap(range, max_gap_left, max_gap_right); BOOST_GEOMETRY_ASSERT(! math::larger(lon_min, lon_max)); BOOST_GEOMETRY_ASSERT (! math::larger(lon_max, constants::max_longitude())); BOOST_GEOMETRY_ASSERT (! math::smaller(lon_min, constants::min_longitude())); BOOST_GEOMETRY_ASSERT (! math::larger(max_gap_left, max_gap_right)); BOOST_GEOMETRY_ASSERT (! math::larger(max_gap_right, constants::max_longitude())); BOOST_GEOMETRY_ASSERT (! math::smaller(max_gap_left, constants::min_longitude())); if (math::larger(max_gap, zero)) { Longitude wrapped_gap = period + lon_min - lon_max; if (math::larger(max_gap, wrapped_gap)) { lon_min = max_gap_right; lon_max = max_gap_left + period; } } } } } }; template <std::size_t Dimension, std::size_t DimensionCount> struct envelope_range_of_boxes_by_expansion { template <typename RangeOfBoxes, typename Box> static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) { typedef typename boost::range_value<RangeOfBoxes>::type box_type; typedef typename boost::range_iterator < RangeOfBoxes const >::type iterator_type; // first initialize MBR detail::indexed_point_view<Box, min_corner> mbr_min(mbr); detail::indexed_point_view<Box, max_corner> mbr_max(mbr); detail::indexed_point_view<box_type const, min_corner> first_box_min(range::front(range_of_boxes)); detail::indexed_point_view<box_type const, max_corner> first_box_max(range::front(range_of_boxes)); detail::conversion::point_to_point < detail::indexed_point_view<box_type const, min_corner>, detail::indexed_point_view<Box, min_corner>, Dimension, DimensionCount >::apply(first_box_min, mbr_min); detail::conversion::point_to_point < detail::indexed_point_view<box_type const, max_corner>, detail::indexed_point_view<Box, max_corner>, Dimension, DimensionCount >::apply(first_box_max, mbr_max); // now expand using the remaining boxes iterator_type it = boost::begin(range_of_boxes); for (++it; it != boost::end(range_of_boxes); ++it) { detail::expand::indexed_loop < min_corner, Dimension, DimensionCount >::apply(mbr, *it); detail::expand::indexed_loop < max_corner, Dimension, DimensionCount >::apply(mbr, *it); } } }; struct envelope_range_of_boxes { template <std::size_t Index> struct latitude_less { template <typename Box> inline bool operator()(Box const& box1, Box const& box2) const { return math::smaller(geometry::get<Index, 1>(box1), geometry::get<Index, 1>(box2)); } }; template <typename RangeOfBoxes, typename Box> static inline void apply(RangeOfBoxes const& range_of_boxes, Box& mbr) { // boxes in the range are assumed to be normalized already typedef typename boost::range_value<RangeOfBoxes>::type box_type; typedef typename coordinate_type<box_type>::type coordinate_type; typedef typename detail::cs_angular_units<box_type>::type units_type; typedef typename boost::range_iterator < RangeOfBoxes const >::type iterator_type; static const bool is_equatorial = ! std::is_same < typename cs_tag<box_type>::type, spherical_polar_tag >::value; typedef math::detail::constants_on_spheroid < coordinate_type, units_type, is_equatorial > constants; typedef longitude_interval<coordinate_type> interval_type; typedef std::vector<interval_type> interval_range_type; BOOST_GEOMETRY_ASSERT(! boost::empty(range_of_boxes)); iterator_type it_min = std::min_element(boost::begin(range_of_boxes), boost::end(range_of_boxes), latitude_less<min_corner>()); iterator_type it_max = std::max_element(boost::begin(range_of_boxes), boost::end(range_of_boxes), latitude_less<max_corner>()); coordinate_type const min_longitude = constants::min_longitude(); coordinate_type const max_longitude = constants::max_longitude(); coordinate_type const period = constants::period(); interval_range_type intervals; for (iterator_type it = boost::begin(range_of_boxes); it != boost::end(range_of_boxes); ++it) { if (is_inverse_spheroidal_coordinates(*it)) { continue; } coordinate_type lat_min = geometry::get<min_corner, 1>(*it); coordinate_type lat_max = geometry::get<max_corner, 1>(*it); if (math::equals(lat_min, constants::max_latitude()) || math::equals(lat_max, constants::min_latitude())) { // if the box degenerates to the south or north pole // just ignore it continue; } coordinate_type lon_left = geometry::get<min_corner, 0>(*it); coordinate_type lon_right = geometry::get<max_corner, 0>(*it); if (math::larger(lon_right, max_longitude)) { intervals.push_back(interval_type(lon_left, max_longitude)); intervals.push_back (interval_type(min_longitude, lon_right - period)); } else { intervals.push_back(interval_type(lon_left, lon_right)); } } coordinate_type lon_min = 0; coordinate_type lon_max = 0; envelope_range_of_longitudes < units_type >::apply(intervals, lon_min, lon_max); // do not convert units; conversion will be performed at a // higher level // assign now the min/max longitude/latitude values detail::indexed_point_view<Box, min_corner> mbr_min(mbr); detail::indexed_point_view<Box, max_corner> mbr_max(mbr); geometry::set<0>(mbr_min, lon_min); geometry::set<1>(mbr_min, geometry::get<min_corner, 1>(*it_min)); geometry::set<0>(mbr_max, lon_max); geometry::set<1>(mbr_max, geometry::get<max_corner, 1>(*it_max)); // what remains to be done is to compute the envelope range // for the remaining dimensions (if any) envelope_range_of_boxes_by_expansion < 2, dimension<Box>::value >::apply(range_of_boxes, mbr); } }; }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_RANGE_OF_BOXES_HPP detail/envelope/interface.hpp 0000644 00000016026 15125631656 0012313 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> #include <boost/geometry/strategies/envelope/services.hpp> #include <boost/geometry/strategy/envelope.hpp> #include <boost/geometry/util/select_most_precise.hpp> namespace boost { namespace geometry { namespace resolve_strategy { template < typename Strategy, bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value > struct envelope { template <typename Geometry, typename Box> static inline void apply(Geometry const& geometry, Box& box, Strategy const& strategy) { dispatch::envelope<Geometry>::apply(geometry, box, strategy); } }; template <typename Strategy> struct envelope<Strategy, false> { template <typename Geometry, typename Box> static inline void apply(Geometry const& geometry, Box& box, Strategy const& strategy) { using strategies::envelope::services::strategy_converter; return dispatch::envelope < Geometry >::apply(geometry, box, strategy_converter<Strategy>::get(strategy)); } }; template <> struct envelope<default_strategy, false> { template <typename Geometry, typename Box> static inline void apply(Geometry const& geometry, Box& box, default_strategy) { typedef typename strategies::envelope::services::default_strategy < Geometry, Box >::type strategy_type; dispatch::envelope<Geometry>::apply(geometry, box, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct envelope { template <typename Box, typename Strategy> static inline void apply(Geometry const& geometry, Box& box, Strategy const& strategy) { concepts::check<Geometry const>(); concepts::check<Box>(); resolve_strategy::envelope<Strategy>::apply(geometry, box, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Box, typename Strategy> struct visitor: boost::static_visitor<void> { Box& m_box; Strategy const& m_strategy; visitor(Box& box, Strategy const& strategy) : m_box(box) , m_strategy(strategy) {} template <typename Geometry> void operator()(Geometry const& geometry) const { envelope<Geometry>::apply(geometry, m_box, m_strategy); } }; template <typename Box, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Box& box, Strategy const& strategy) { boost::apply_visitor(visitor<Box, Strategy>(box, strategy), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{envelope (with strategy)} \ingroup envelope \details \details_calc{envelope,\det_envelope}. \tparam Geometry \tparam_geometry \tparam Box \tparam_box \tparam Strategy \tparam_strategy{Envelope} \param geometry \param_geometry \param mbr \param_box \param_set{envelope} \param strategy \param_strategy{envelope} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/envelope.qbk]} \qbk{ [heading Example] [envelope] [envelope_output] } */ template<typename Geometry, typename Box, typename Strategy> inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy) { resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy); } /*! \brief \brief_calc{envelope} \ingroup envelope \details \details_calc{envelope,\det_envelope}. \tparam Geometry \tparam_geometry \tparam Box \tparam_box \param geometry \param_geometry \param mbr \param_box \param_set{envelope} \qbk{[include reference/algorithms/envelope.qbk]} \qbk{ [heading Example] [envelope] [envelope_output] } */ template<typename Geometry, typename Box> inline void envelope(Geometry const& geometry, Box& mbr) { resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy()); } /*! \brief \brief_calc{envelope} \ingroup envelope \details \details_calc{return_envelope,\det_envelope}. \details_return{envelope} \tparam Box \tparam_box \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Envelope} \param geometry \param_geometry \param strategy \param_strategy{envelope} \return \return_calc{envelope} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/envelope.qbk]} \qbk{ [heading Example] [return_envelope] [return_envelope_output] } */ template<typename Box, typename Geometry, typename Strategy> inline Box return_envelope(Geometry const& geometry, Strategy const& strategy) { Box mbr; resolve_variant::envelope<Geometry>::apply(geometry, mbr, strategy); return mbr; } /*! \brief \brief_calc{envelope} \ingroup envelope \details \details_calc{return_envelope,\det_envelope}. \details_return{envelope} \tparam Box \tparam_box \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{envelope} \qbk{[include reference/algorithms/envelope.qbk]} \qbk{ [heading Example] [return_envelope] [return_envelope_output] } */ template<typename Box, typename Geometry> inline Box return_envelope(Geometry const& geometry) { Box mbr; resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy()); return mbr; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP detail/envelope/segment.hpp 0000644 00000006421 15125631656 0012013 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP #include <cstddef> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> // TEMP #include <boost/geometry/strategies/detail.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { // TEMP template < typename Strategy, bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value > struct envelope_segment_call_strategy { template <typename Point, typename Segment, typename Box> static inline void apply(Point const& p1, Point const& p2, Segment const& segment, Box& mbr, Strategy const& strategy) { strategy.envelope(segment, mbr).apply(p1, p2, mbr); } }; template <typename Strategy> struct envelope_segment_call_strategy<Strategy, false> { template <typename Point, typename Segment, typename Box> static inline void apply(Point const& p1, Point const& p2, Segment const&, Box& mbr, Strategy const& strategy) { strategy.apply(p1, p2, mbr); } }; struct envelope_segment { template <typename Segment, typename Box, typename Strategy> static inline void apply(Segment const& segment, Box& mbr, Strategy const& strategy) { typename point_type<Segment>::type p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); // TEMP - expand calls this and Umbrella strategies are not yet supported there envelope_segment_call_strategy<Strategy>::apply(p[0], p[1], segment, mbr, strategy); } }; }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Segment> struct envelope<Segment, segment_tag> { template <typename Box, typename Strategy> static inline void apply(Segment const& segment, Box& mbr, Strategy const& strategy) { detail::envelope::envelope_segment /*< dimension<Segment>::value >*/::apply(segment, mbr, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_SEGMENT_HPP detail/envelope/point.hpp 0000644 00000003405 15125631656 0011501 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/dispatch/envelope.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace envelope { struct envelope_point { template <typename Point, typename Box, typename Strategy> static inline void apply(Point const& point, Box& mbr, Strategy const& strategy) { // strategy.envelope(point, mbr).apply(point, mbr); using strategy_t = decltype(strategy.envelope(point, mbr)); strategy_t::apply(point, mbr); } }; }} // namespace detail::envelope #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point> struct envelope<Point, point_tag> : detail::envelope::envelope_point {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP detail/sub_range.hpp 0000644 00000007666 15125631656 0010515 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP #include <type_traits> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type, bool IsMulti = std::is_base_of<multi_tag, Tag>::value> struct sub_range : not_implemented<Tag> {}; template <typename Geometry, typename Tag> struct sub_range<Geometry, Tag, false> { typedef Geometry & return_type; template <typename Id> static inline return_type apply(Geometry & geometry, Id const&) { return geometry; } }; template <typename Geometry> struct sub_range<Geometry, polygon_tag, false> { typedef typename geometry::ring_return_type<Geometry>::type return_type; template <typename Id> static inline return_type apply(Geometry & geometry, Id const& id) { if ( id.ring_index < 0 ) { return geometry::exterior_ring(geometry); } else { typedef typename boost::range_size < typename geometry::interior_type<Geometry>::type >::type size_type; size_type const ri = static_cast<size_type>(id.ring_index); return range::at(geometry::interior_rings(geometry), ri); } } }; template <typename Geometry, typename Tag> struct sub_range<Geometry, Tag, true> { typedef typename boost::range_value<Geometry>::type value_type; typedef std::conditional_t < std::is_const<Geometry>::value, typename std::add_const<value_type>::type, value_type > sub_type; typedef detail_dispatch::sub_range<sub_type> sub_sub_range; // TODO: shouldn't it be return_type? typedef typename sub_sub_range::return_type return_type; template <typename Id> static inline return_type apply(Geometry & geometry, Id const& id) { BOOST_GEOMETRY_ASSERT(0 <= id.multi_index); typedef typename boost::range_size<Geometry>::type size_type; size_type const mi = static_cast<size_type>(id.multi_index); return sub_sub_range::apply(range::at(geometry, mi), id); } }; } // namespace detail_dispatch #endif // DOXYGEN_NO_DISPATCH namespace detail { template <typename Geometry> struct sub_range_return_type { typedef typename detail_dispatch::sub_range<Geometry>::return_type type; }; // This function also works for geometry::segment_identifier template <typename Geometry, typename Id> inline typename sub_range_return_type<Geometry>::type sub_range(Geometry & geometry, Id const& id) { return detail_dispatch::sub_range<Geometry>::apply(geometry, id); } template <typename Geometry, typename Id> inline typename sub_range_return_type<Geometry const>::type sub_range(Geometry const& geometry, Id const& id) { return detail_dispatch::sub_range<Geometry const>::apply(geometry, id); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP detail/multi_sum.hpp 0000644 00000003256 15125631656 0010555 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { struct multi_sum { template <typename ReturnType, typename Policy, typename MultiGeometry, typename Strategy> static inline ReturnType apply(MultiGeometry const& geometry, Strategy const& strategy) { ReturnType sum = ReturnType(); for (typename boost::range_iterator < MultiGeometry const >::type it = boost::begin(geometry); it != boost::end(geometry); ++it) { sum += Policy::apply(*it, strategy); } return sum; } }; } // namespace detail #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_SUM_HPP detail/tupled_output.hpp 0000644 00000036764 15125631656 0011466 0 ustar 00 // Boost.Geometry // Copyright (c) 2019-2020, 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_DETAIL_TUPLED_OUTPUT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/core/config.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/util/tuples.hpp> #include <boost/geometry/util/type_traits.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename T, bool IsRange = range::detail::is_range<T>::value> struct is_tupled_output_element_base : util::bool_constant<false> {}; template <typename T> struct is_tupled_output_element_base<T, true> : util::bool_constant < (util::is_multi<T>::value || (util::is_not_geometry<T>::value && util::is_multi_element < typename boost::range_value<T>::type >::value)) > {}; // true if T is a multi-geometry or is a range of points, linestrings or // polygons template <typename T> struct is_tupled_output_element : is_tupled_output_element_base<T> {}; // true if Output is not a geometry (so e.g. tuple was not adapted to any // concept) and at least one of the tuple elements is a multi-geometry or // a range of points, linestrings or polygons template <typename Output> struct is_tupled_output_check : util::bool_constant < (util::is_not_geometry<Output>::value && geometry::tuples::exists_if<Output, is_tupled_output_element>::value) > {}; // true if T is not a geometry (so e.g. tuple was not adapted to any // concept) and at least one of the tuple elements is a point, linesting // or polygon template <typename T> struct is_tupled_single_output_check : util::bool_constant < (util::is_not_geometry<T>::value && geometry::tuples::exists_if<T, util::is_multi_element>::value) > {}; // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple // and is_tupled_output_check defiend above passes template <typename Output, bool IsTupled = tuples::is_tuple<Output>::value> struct is_tupled_output : util::bool_constant<false> {}; template <typename Output> struct is_tupled_output<Output, true> : is_tupled_output_check<Output> {}; // true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple // and is_tupled_single_output_check defiend above passes template <typename T, bool IsTupled = tuples::is_tuple<T>::value> struct is_tupled_single_output : util::bool_constant<false> {}; template <typename T> struct is_tupled_single_output<T, true> : is_tupled_single_output_check<T> {}; template <typename Tag> struct tupled_output_find_index_pred { template <typename T> struct pred : std::is_same<typename geometry::tag<T>::type, Tag> {}; }; // Valid only if tupled_output_has<Output, Tag> is true template <typename Output, typename Tag> struct tupled_output_find_index : geometry::tuples::find_index_if < Output, tupled_output_find_index_pred<Tag>::template pred > {}; template < typename Output, typename Tag, bool IsTupledOutput = is_tupled_output<Output>::value > struct tupled_output_has : util::bool_constant<false> {}; template <typename Output, typename Tag> struct tupled_output_has<Output, Tag, true> : util::bool_constant < ((tupled_output_find_index<Output, Tag>::value) < (geometry::tuples::size<Output>::value)) > {}; // Valid only if tupled_output_has<Output, Tag> is true template <typename Tag, typename Output> inline typename geometry::tuples::element < tupled_output_find_index<Output, Tag>::value, Output >::type & tupled_output_get(Output & output) { return geometry::tuples::get<tupled_output_find_index<Output, Tag>::value>(output); } // defines a tuple-type holding value-types of ranges being elements of // Output pair/tuple template <typename Tuple> struct tupled_range_values; template <typename ...Ts> struct tupled_range_values<std::tuple<Ts...> > { typedef std::tuple<typename boost::range_value<Ts>::type...> type; }; template <typename F, typename S> struct tupled_range_values<std::pair<F, S> > { typedef std::pair < typename boost::range_value<F>::type, typename boost::range_value<S>::type > type; }; template < typename Tuple, size_t I = 0, size_t N = boost::tuples::length<Tuple>::value > struct tupled_range_values_bt { typedef boost::tuples::cons < typename boost::range_value < typename boost::tuples::element<I, Tuple>::type >::type, typename tupled_range_values_bt<Tuple, I+1, N>::type > type; }; template <typename Tuple, size_t N> struct tupled_range_values_bt<Tuple, N, N> { typedef boost::tuples::null_type type; }; template <typename ...Ts> struct tupled_range_values<boost::tuples::tuple<Ts...>> : tupled_range_values_bt<boost::tuples::tuple<Ts...>> {}; template <typename HT, typename TT> struct tupled_range_values<boost::tuples::cons<HT, TT>> : tupled_range_values_bt<boost::tuples::cons<HT, TT>> {}; // util defining a type and creating a tuple holding back-insert-iterators to // ranges being elements of Output pair/tuple template <typename Tuple> struct tupled_back_inserters; template <typename Is, typename Tuple> struct tupled_back_inserters_st; template <std::size_t ...Is, typename ...Ts> struct tupled_back_inserters_st<std::index_sequence<Is...>, std::tuple<Ts...> > { typedef std::tuple<geometry::range::back_insert_iterator<Ts>...> type; static type apply(std::tuple<Ts...> & tup) { return type(geometry::range::back_inserter(std::get<Is>(tup))...); } }; template <typename ...Ts> struct tupled_back_inserters<std::tuple<Ts...> > : tupled_back_inserters_st < std::make_index_sequence<sizeof...(Ts)>, std::tuple<Ts...> > {}; template <typename F, typename S> struct tupled_back_inserters<std::pair<F, S> > { typedef std::pair < geometry::range::back_insert_iterator<F>, geometry::range::back_insert_iterator<S> > type; static type apply(std::pair<F, S> & p) { return type(geometry::range::back_inserter(p.first), geometry::range::back_inserter(p.second)); } }; template <typename Tuple, size_t I = 0, size_t N = boost::tuples::length<Tuple>::value> struct tupled_back_inserters_bt { typedef boost::tuples::cons < geometry::range::back_insert_iterator < typename boost::tuples::element<I, Tuple>::type >, typename tupled_back_inserters_bt<Tuple, I+1, N>::type > type; static type apply(Tuple & tup) { return type(geometry::range::back_inserter(boost::get<I>(tup)), tupled_back_inserters_bt<Tuple, I+1, N>::apply(tup)); } }; template <typename Tuple, size_t N> struct tupled_back_inserters_bt<Tuple, N, N> { typedef boost::tuples::null_type type; static type apply(Tuple const&) { return type(); } }; template <typename ...Ts> struct tupled_back_inserters<boost::tuples::tuple<Ts...>> : tupled_back_inserters_bt<boost::tuples::tuple<Ts...>> {}; template <typename HT, typename TT> struct tupled_back_inserters<boost::tuples::cons<HT, TT>> : tupled_back_inserters_bt<boost::tuples::cons<HT, TT>> {}; template < typename GeometryOut, bool IsTupled = is_tupled_output<GeometryOut>::value > struct output_geometry_value : boost::range_value<GeometryOut> {}; template <typename GeometryOut> struct output_geometry_value<GeometryOut, true> : tupled_range_values<GeometryOut> {}; template < typename GeometryOut, bool IsTupled = is_tupled_output<GeometryOut>::value > struct output_geometry_back_inserter_ { typedef geometry::range::back_insert_iterator<GeometryOut> type; static type apply(GeometryOut & out) { return geometry::range::back_inserter(out); } }; template <typename GeometryOut> struct output_geometry_back_inserter_<GeometryOut, true> : tupled_back_inserters<GeometryOut> {}; template <typename GeometryOut> inline typename output_geometry_back_inserter_<GeometryOut>::type output_geometry_back_inserter(GeometryOut & out) { return output_geometry_back_inserter_<GeometryOut>::apply(out); } // is_tag_same_as_pred // Defines a predicate true if type's tag is the same as Tag template <typename Tag> struct is_tag_same_as_pred { template <typename T> struct pred : std::is_same<typename geometry::tag<T>::type, Tag> {}; }; // Allows to access a type/object in a pair/tuple corresponding to an index in // GeometryOut pair/tuple of a geometry defined by Tag. // If GeometryOut is a geometry then it's expected to be defined by DefaultTag. template < typename GeometryOut, typename Tag, typename DefaultTag, typename GeometryTag = typename geometry::tag<GeometryOut>::type > struct output_geometry_access {}; // assume GeometryTag is void because not adapted tuple holding geometries was passed template <typename TupledOut, typename Tag, typename DefaultTag> struct output_geometry_access<TupledOut, Tag, DefaultTag, void> { static const int index = geometry::tuples::find_index_if < TupledOut, is_tag_same_as_pred<Tag>::template pred >::value; typedef typename geometry::tuples::element<index, TupledOut>::type type; template <typename Tuple> static typename geometry::tuples::element<index, Tuple>::type& get(Tuple & tup) { return geometry::tuples::get<index>(tup); } }; template <typename GeometryOut, typename Tag, typename DefaultTag> struct output_geometry_access<GeometryOut, Tag, DefaultTag, DefaultTag> { typedef GeometryOut type; template <typename T> static T& get(T & v) { return v; } }; template <typename Geometry> struct output_geometry_concept_check { static void apply() { concepts::check<Geometry>(); } }; template <typename First, typename Second> struct output_geometry_concept_check<std::pair<First, Second> > { static void apply() { concepts::check<First>(); concepts::check<Second>(); } }; template <typename Tuple, size_t I = 0, size_t N = geometry::tuples::size<Tuple>::value> struct output_geometry_concept_check_t { static void apply() { concepts::check<typename geometry::tuples::element<I, Tuple>::type>(); output_geometry_concept_check_t<Tuple, I + 1, N>::apply(); } }; template <typename Tuple, size_t N> struct output_geometry_concept_check_t<Tuple, N, N> { static void apply() {} }; template <typename ...Ts> struct output_geometry_concept_check<std::tuple<Ts...> > : output_geometry_concept_check_t<std::tuple<Ts...> > {}; template <typename ...Ts> struct output_geometry_concept_check<boost::tuple<Ts...> > : output_geometry_concept_check_t<boost::tuple<Ts...> > {}; template <typename HT, typename TT> struct output_geometry_concept_check<boost::tuples::cons<HT, TT> > : output_geometry_concept_check_t<boost::tuples::cons<HT, TT> > {}; struct tupled_output_tag {}; template <typename GeometryOut> struct setop_insert_output_tag : std::conditional < geometry::detail::is_tupled_single_output<GeometryOut>::value, tupled_output_tag, typename geometry::tag<GeometryOut>::type > {}; template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound, typename Tag> struct expect_output_assert_base; template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound> struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, pointlike_tag> { BOOST_GEOMETRY_STATIC_ASSERT( IsFound, "PointLike Geometry expected in tupled output.", Geometry1, Geometry2, TupledOut); }; template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound> struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, linear_tag> { BOOST_GEOMETRY_STATIC_ASSERT( IsFound, "Linear Geometry expected in tupled output.", Geometry1, Geometry2, TupledOut); }; template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound> struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, areal_tag> { BOOST_GEOMETRY_STATIC_ASSERT( IsFound, "Areal Geometry expected in tupled output.", Geometry1, Geometry2, TupledOut); }; template <typename Geometry1, typename Geometry2, typename TupledOut, typename Tag> struct expect_output_assert : expect_output_assert_base < Geometry1, Geometry2, TupledOut, geometry::tuples::exists_if < TupledOut, is_tag_same_as_pred<Tag>::template pred >::value, typename geometry::tag_cast < Tag, pointlike_tag, linear_tag, areal_tag >::type > {}; template <typename Geometry1, typename Geometry2, typename TupledOut> struct expect_output_assert<Geometry1, Geometry2, TupledOut, void> {}; template < typename Geometry1, typename Geometry2, typename TupledOut, typename ...Tags > struct expect_output : expect_output_assert<Geometry1, Geometry2, TupledOut, Tags>... {}; template <typename CastedTag> struct single_tag_from_base_tag; template <> struct single_tag_from_base_tag<pointlike_tag> { typedef point_tag type; }; template <> struct single_tag_from_base_tag<linear_tag> { typedef linestring_tag type; }; template <> struct single_tag_from_base_tag<areal_tag> { typedef polygon_tag type; }; template < typename Geometry, typename SingleOut, bool IsMulti = util::is_multi<Geometry>::value > struct convert_to_output { template <typename OutputIterator> static OutputIterator apply(Geometry const& geometry, OutputIterator oit) { SingleOut single_out; geometry::convert(geometry, single_out); *oit++ = single_out; return oit; } }; template < typename Geometry, typename SingleOut > struct convert_to_output<Geometry, SingleOut, true> { template <typename OutputIterator> static OutputIterator apply(Geometry const& geometry, OutputIterator oit) { typedef typename boost::range_iterator<Geometry const>::type iterator; for (iterator it = boost::begin(geometry); it != boost::end(geometry); ++it) { SingleOut single_out; geometry::convert(*it, single_out); *oit++ = single_out; } return oit; } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP detail/sections/section_box_policies.hpp 0000644 00000003477 15125631656 0014576 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018. // Modifications copyright (c) 2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/expand.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace section { template <typename ExpandBoxStrategy> struct get_section_box { template <typename Box, typename Section> static inline void apply(Box& total, Section const& section) { assert_coordinate_type_equal(total, section.bounding_box); geometry::expand(total, section.bounding_box, ExpandBoxStrategy()); } }; template <typename DisjointBoxBoxStrategy> struct overlaps_section_box { template <typename Box, typename Section> static inline bool apply(Box const& box, Section const& section) { assert_coordinate_type_equal(box, section.bounding_box); return ! detail::disjoint::disjoint_box_box(box, section.bounding_box, DisjointBoxBoxStrategy()); } }; }} // namespace detail::section #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP detail/sections/sectionalize.hpp 0000644 00000100076 15125631656 0013055 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP #include <cstddef> #include <type_traits> #include <vector> #include <boost/concept/requires.hpp> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/config.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> #include <boost/geometry/policies/robustness/robust_point_type.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> #include <boost/geometry/util/sequence.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> // TEMP #include <boost/geometry/strategy/envelope.hpp> #include <boost/geometry/strategy/expand.hpp> namespace boost { namespace geometry { /*! \brief Structure containing section information \details Section information consists of a bounding box, direction information (if it is increasing or decreasing, per dimension), index information (begin-end, ring, multi) and the number of segments in this section \tparam Box box-type \tparam DimensionCount number of dimensions for this section \ingroup sectionalize */ template < typename Box, std::size_t DimensionCount > struct section { typedef Box box_type; static std::size_t const dimension_count = DimensionCount; int directions[DimensionCount]; ring_identifier ring_id; Box bounding_box; // NOTE: size_type could be passed as template parameter // NOTE: these probably also could be of type std::size_t signed_size_type begin_index; signed_size_type end_index; std::size_t count; std::size_t range_count; bool duplicate; signed_size_type non_duplicate_index; bool is_non_duplicate_first; bool is_non_duplicate_last; inline section() : begin_index(-1) , end_index(-1) , count(0) , range_count(0) , duplicate(false) , non_duplicate_index(-1) , is_non_duplicate_first(false) , is_non_duplicate_last(false) { assign_inverse(bounding_box); for (std::size_t i = 0; i < DimensionCount; i++) { directions[i] = 0; } } }; /*! \brief Structure containing a collection of sections \note Derived from a vector, proves to be faster than of deque \note vector might be templated in the future \ingroup sectionalize */ template <typename Box, std::size_t DimensionCount> struct sections : std::vector<section<Box, DimensionCount> > { typedef Box box_type; static std::size_t const value = DimensionCount; }; #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace sectionalize { // NOTE: This utility will NOT work for latitudes, dimension 1 in spherical // and geographic coordinate system because in these coordinate systems // e.g. a segment on northern hemisphere may go towards greater latitude // and then towards lesser latitude. template < typename Point, typename DimensionVector, std::size_t Index, std::size_t Count, typename CastedCSTag = typename tag_cast < typename cs_tag<Point>::type, spherical_tag >::type > struct get_direction_loop { typedef typename util::sequence_element<Index, DimensionVector>::type dimension; template <typename Segment> static inline void apply(Segment const& seg, int directions[Count]) { typedef typename coordinate_type<Segment>::type coordinate_type; coordinate_type const c0 = geometry::get<0, dimension::value>(seg); coordinate_type const c1 = geometry::get<1, dimension::value>(seg); directions[Index] = c1 > c0 ? 1 : c1 < c0 ? -1 : 0; get_direction_loop < Point, DimensionVector, Index + 1, Count, CastedCSTag >::apply(seg, directions); } }; template < typename Point, typename DimensionVector, std::size_t Count > struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag> { typedef typename util::sequence_element<0, DimensionVector>::type dimension; template <typename Segment> static inline void apply(Segment const& seg, int directions[Count]) { typedef typename coordinate_type<Segment>::type coordinate_type; typedef typename coordinate_system<Point>::type::units units_t; coordinate_type const diff = math::longitude_distance_signed < units_t, coordinate_type >(geometry::get<0, 0>(seg), geometry::get<1, 0>(seg)); coordinate_type zero = coordinate_type(); directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0; get_direction_loop < Point, DimensionVector, 1, Count, spherical_tag >::apply(seg, directions); } }; template < typename Point, typename DimensionVector, std::size_t Count, typename CastedCSTag > struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag> { template <typename Segment> static inline void apply(Segment const&, int [Count]) {} }; //! Copy one static array to another template <typename T, std::size_t Index, std::size_t Count> struct copy_loop { static inline void apply(T const source[Count], T target[Count]) { target[Index] = source[Index]; copy_loop<T, Index + 1, Count>::apply(source, target); } }; template <typename T, std::size_t Count> struct copy_loop<T, Count, Count> { static inline void apply(T const [Count], T [Count]) {} }; //! Compare two static arrays template <typename T, std::size_t Index, std::size_t Count> struct compare_loop { static inline bool apply(T const array1[Count], T const array2[Count]) { return array1[Index] != array2[Index] ? false : compare_loop < T, Index + 1, Count >::apply(array1, array2); } }; template <typename T, std::size_t Count> struct compare_loop<T, Count, Count> { static inline bool apply(T const [Count], T const [Count]) { return true; } }; template <std::size_t Dimension, std::size_t DimensionCount> struct check_duplicate_loop { template <typename Segment> static inline bool apply(Segment const& seg) { if (! geometry::math::equals ( geometry::get<0, Dimension>(seg), geometry::get<1, Dimension>(seg) ) ) { return false; } return check_duplicate_loop < Dimension + 1, DimensionCount >::apply(seg); } }; template <std::size_t DimensionCount> struct check_duplicate_loop<DimensionCount, DimensionCount> { template <typename Segment> static inline bool apply(Segment const&) { return true; } }; //! Assign a value to a static array template <typename T, std::size_t Index, std::size_t Count> struct assign_loop { static inline void apply(T dims[Count], T const value) { dims[Index] = value; assign_loop<T, Index + 1, Count>::apply(dims, value); } }; template <typename T, std::size_t Count> struct assign_loop<T, Count, Count> { static inline void apply(T [Count], T const) { } }; template <typename CSTag> struct box_first_in_section { template <typename Box, typename Point, typename EnvelopeStrategy> static inline void apply(Box & box, Point const& prev, Point const& curr, EnvelopeStrategy const& strategy) { geometry::model::referring_segment<Point const> seg(prev, curr); geometry::envelope(seg, box, strategy); } }; template <> struct box_first_in_section<cartesian_tag> { template <typename Box, typename Point, typename ExpandStrategy> static inline void apply(Box & box, Point const& prev, Point const& curr, ExpandStrategy const& ) { geometry::envelope(prev, box); geometry::expand(box, curr); } }; template <typename CSTag> struct box_next_in_section { template <typename Box, typename Point, typename Strategy> static inline void apply(Box & box, Point const& prev, Point const& curr, Strategy const& strategy) { geometry::model::referring_segment<Point const> seg(prev, curr); geometry::expand(box, seg, strategy); } }; template <> struct box_next_in_section<cartesian_tag> { template <typename Box, typename Point, typename Strategy> static inline void apply(Box & box, Point const& , Point const& curr, Strategy const& ) { geometry::expand(box, curr); } }; /// @brief Helper class to create sections of a part of a range, on the fly template < typename Point, typename DimensionVector > struct sectionalize_part { static const std::size_t dimension_count = util::sequence_size<DimensionVector>::value; template < typename Iterator, typename RobustPolicy, typename Sections > static inline void apply(Sections& sections, Iterator begin, Iterator end, RobustPolicy const& robust_policy, ring_identifier ring_id, std::size_t max_count) { typedef typename strategy::envelope::services::default_strategy < segment_tag, typename cs_tag<typename Sections::box_type>::type >::type envelope_strategy_type; typedef typename strategy::expand::services::default_strategy < segment_tag, typename cs_tag<typename Sections::box_type>::type >::type expand_strategy_type; apply(sections, begin, end, robust_policy, envelope_strategy_type(), expand_strategy_type(), ring_id, max_count); } template < typename Iterator, typename RobustPolicy, typename Sections, typename EnvelopeStrategy, typename ExpandStrategy > static inline void apply(Sections& sections, Iterator begin, Iterator end, RobustPolicy const& robust_policy, EnvelopeStrategy const& envelope_strategy, ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { boost::ignore_unused(robust_policy); typedef typename boost::range_value<Sections>::type section_type; BOOST_STATIC_ASSERT ( section_type::dimension_count == util::sequence_size<DimensionVector>::value ); typedef typename geometry::robust_point_type < Point, RobustPolicy >::type robust_point_type; std::size_t const count = std::distance(begin, end); if (count == 0) { return; } signed_size_type index = 0; signed_size_type ndi = 0; // non duplicate index section_type section; bool mark_first_non_duplicated = true; std::size_t last_non_duplicate_index = sections.size(); Iterator it = begin; robust_point_type previous_robust_point; geometry::recalculate(previous_robust_point, *it, robust_policy); for(Iterator previous = it++; it != end; ++previous, ++it, index++) { robust_point_type current_robust_point; geometry::recalculate(current_robust_point, *it, robust_policy); model::referring_segment<robust_point_type> robust_segment( previous_robust_point, current_robust_point); int direction_classes[dimension_count] = {0}; get_direction_loop < Point, DimensionVector, 0, dimension_count >::apply(robust_segment, direction_classes); // if "dir" == 0 for all point-dimensions, it is duplicate. // Those sections might be omitted, if wished, lateron bool duplicate = false; if (direction_classes[0] == 0) { // Recheck because ALL dimensions should be checked, // not only first one. // (dimension_count might be < dimension<P>::value) if (check_duplicate_loop < 0, geometry::dimension<Point>::type::value >::apply(robust_segment) ) { duplicate = true; // Change direction-info to force new section // Note that wo consecutive duplicate segments will generate // only one duplicate-section. // Actual value is not important as long as it is not -1,0,1 assign_loop < int, 0, dimension_count >::apply(direction_classes, -99); } } if (section.count > 0 && (! compare_loop < int, 0, dimension_count >::apply(direction_classes, section.directions) || section.count > max_count) ) { if (! section.duplicate) { last_non_duplicate_index = sections.size(); } sections.push_back(section); section = section_type(); } if (section.count == 0) { section.begin_index = index; section.ring_id = ring_id; section.duplicate = duplicate; section.non_duplicate_index = ndi; section.range_count = count; if (mark_first_non_duplicated && ! duplicate) { section.is_non_duplicate_first = true; mark_first_non_duplicated = false; } copy_loop < int, 0, dimension_count >::apply(direction_classes, section.directions); // In cartesian this is envelope of previous point expanded with current point // in non-cartesian this is envelope of a segment box_first_in_section<typename cs_tag<robust_point_type>::type> ::apply(section.bounding_box, previous_robust_point, current_robust_point, envelope_strategy); } else { // In cartesian this is expand with current point // in non-cartesian this is expand with a segment box_next_in_section<typename cs_tag<robust_point_type>::type> ::apply(section.bounding_box, previous_robust_point, current_robust_point, expand_strategy); } section.end_index = index + 1; section.count++; if (! duplicate) { ndi++; } previous_robust_point = current_robust_point; } // Add last section if applicable if (section.count > 0) { if (! section.duplicate) { last_non_duplicate_index = sections.size(); } sections.push_back(section); } if (last_non_duplicate_index < sections.size() && ! sections[last_non_duplicate_index].duplicate) { sections[last_non_duplicate_index].is_non_duplicate_last = true; } } }; template < closure_selector Closure, bool Reverse, typename Point, typename DimensionVector > struct sectionalize_range { template < typename Range, typename RobustPolicy, typename Sections, typename EnvelopeStrategy, typename ExpandStrategy > static inline void apply(Range const& range, RobustPolicy const& robust_policy, Sections& sections, EnvelopeStrategy const& envelope_strategy, ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { typedef typename closeable_view<Range const, Closure>::type cview_type; typedef typename reversible_view < cview_type const, Reverse ? iterate_reverse : iterate_forward >::type view_type; cview_type cview(range); view_type view(cview); std::size_t const n = boost::size(view); if (n == 0) { // Zero points, no section return; } if (n == 1) { // Line with one point ==> no sections return; } sectionalize_part<Point, DimensionVector>::apply(sections, boost::begin(view), boost::end(view), robust_policy, envelope_strategy, expand_strategy, ring_id, max_count); } }; template < bool Reverse, typename DimensionVector > struct sectionalize_polygon { template < typename Polygon, typename RobustPolicy, typename Sections, typename EnvelopeStrategy, typename ExpandStrategy > static inline void apply(Polygon const& poly, RobustPolicy const& robust_policy, Sections& sections, EnvelopeStrategy const& envelope_strategy, ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { typedef typename point_type<Polygon>::type point_type; typedef sectionalize_range < closure<Polygon>::value, Reverse, point_type, DimensionVector > per_range; ring_id.ring_index = -1; per_range::apply(exterior_ring(poly), robust_policy, sections, envelope_strategy, expand_strategy, ring_id, max_count); ring_id.ring_index++; typename interior_return_type<Polygon const>::type rings = interior_rings(poly); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index) { per_range::apply(*it, robust_policy, sections, envelope_strategy, expand_strategy, ring_id, max_count); } } }; template <typename DimensionVector> struct sectionalize_box { template < typename Box, typename RobustPolicy, typename Sections, typename EnvelopeStrategy, typename ExpandStrategy > static inline void apply(Box const& box, RobustPolicy const& robust_policy, Sections& sections, EnvelopeStrategy const& envelope_strategy, ExpandStrategy const& expand_strategy, ring_identifier const& ring_id, std::size_t max_count) { typedef typename point_type<Box>::type point_type; assert_dimension<Box, 2>(); // Add all four sides of the 2D-box as separate section. // Easiest is to convert it to a polygon. // However, we don't have the polygon type // (or polygon would be a helper-type). // Therefore we mimic a linestring/std::vector of 5 points // TODO: might be replaced by assign_box_corners_oriented // or just "convert" point_type ll, lr, ul, ur; geometry::detail::assign_box_corners(box, ll, lr, ul, ur); std::vector<point_type> points; points.push_back(ll); points.push_back(ul); points.push_back(ur); points.push_back(lr); points.push_back(ll); // NOTE: Use cartesian envelope strategy in all coordinate systems // because edges of a box are not geodesic segments sectionalize_range < closed, false, point_type, DimensionVector >::apply(points, robust_policy, sections, envelope_strategy, expand_strategy, ring_id, max_count); } }; template <typename DimensionVector, typename Policy> struct sectionalize_multi { template < typename MultiGeometry, typename RobustPolicy, typename Sections, typename EnvelopeStrategy, typename ExpandStrategy > static inline void apply(MultiGeometry const& multi, RobustPolicy const& robust_policy, Sections& sections, EnvelopeStrategy const& envelope_strategy, ExpandStrategy const& expand_strategy, ring_identifier ring_id, std::size_t max_count) { ring_id.multi_index = 0; for (typename boost::range_iterator<MultiGeometry const>::type it = boost::begin(multi); it != boost::end(multi); ++it, ++ring_id.multi_index) { Policy::apply(*it, robust_policy, sections, envelope_strategy, expand_strategy, ring_id, max_count); } } }; // TODO: If it depends on CS it should probably be made into strategy. // For now implemented here because of ongoing work on robustness // the fact that it interferes with detail::buffer::buffer_box // and that we probably need a general strategy for defining epsilon in // various coordinate systems, e.g. for point comparison, enlargement of // bounding boxes, etc. template <typename CSTag> struct expand_by_epsilon : not_implemented<CSTag> {}; template <> struct expand_by_epsilon<cartesian_tag> { template <typename Box> static inline void apply(Box & box) { detail::expand_by_epsilon(box); } }; template <> struct expand_by_epsilon<spherical_tag> { template <typename Box> static inline void apply(Box & box) { typedef typename coordinate_type<Box>::type coord_t; static const coord_t eps = std::is_same<coord_t, float>::value ? coord_t(1e-6) : coord_t(1e-12); detail::expand_by_epsilon(box, eps); } }; // TODO: In geographic CS it should probably also depend on FormulaPolicy. template <> struct expand_by_epsilon<geographic_tag> : expand_by_epsilon<spherical_tag> {}; template <typename Sections, typename Strategy> inline void enlarge_sections(Sections& sections, Strategy const&) { // Enlarge sections slightly, this should be consistent with math::equals() // and with the tolerances used in general_form intersections. // This avoids missing turns. // Points and Segments are equal-compared WRT machine epsilon, but Boxes aren't // Enlarging Boxes ensures that they correspond to the bound objects, // Segments in this case, since Sections are collections of Segments. // It makes section a tiny bit too large, which might cause (a small number) // of more comparisons for (typename boost::range_iterator<Sections>::type it = boost::begin(sections); it != boost::end(sections); ++it) { #if defined(BOOST_GEOMETRY_USE_RESCALING) detail::sectionalize::expand_by_epsilon < typename Strategy::cs_tag >::apply(it->bounding_box); #else // Expand the box to avoid missing any intersection. The amount is // should be larger than epsilon. About the value itself: the smaller // it is, the higher the risk to miss intersections. The larger it is, // the more comparisons are made. So it should be on the high side. detail::buffer::buffer_box(it->bounding_box, 0.001, it->bounding_box); #endif } } }} // namespace detail::sectionalize #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Tag, typename Geometry, bool Reverse, typename DimensionVector > struct sectionalize { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for this Geometry type.", Tag, Geometry); }; template < typename Box, bool Reverse, typename DimensionVector > struct sectionalize<box_tag, Box, Reverse, DimensionVector> : detail::sectionalize::sectionalize_box<DimensionVector> {}; template < typename LineString, typename DimensionVector > struct sectionalize < linestring_tag, LineString, false, DimensionVector > : detail::sectionalize::sectionalize_range < closed, false, typename point_type<LineString>::type, DimensionVector > {}; template < typename Ring, bool Reverse, typename DimensionVector > struct sectionalize<ring_tag, Ring, Reverse, DimensionVector> : detail::sectionalize::sectionalize_range < geometry::closure<Ring>::value, Reverse, typename point_type<Ring>::type, DimensionVector > {}; template < typename Polygon, bool Reverse, typename DimensionVector > struct sectionalize<polygon_tag, Polygon, Reverse, DimensionVector> : detail::sectionalize::sectionalize_polygon < Reverse, DimensionVector > {}; template < typename MultiPolygon, bool Reverse, typename DimensionVector > struct sectionalize<multi_polygon_tag, MultiPolygon, Reverse, DimensionVector> : detail::sectionalize::sectionalize_multi < DimensionVector, detail::sectionalize::sectionalize_polygon < Reverse, DimensionVector > > {}; template < typename MultiLinestring, bool Reverse, typename DimensionVector > struct sectionalize<multi_linestring_tag, MultiLinestring, Reverse, DimensionVector> : detail::sectionalize::sectionalize_multi < DimensionVector, detail::sectionalize::sectionalize_range < closed, false, typename point_type<MultiLinestring>::type, DimensionVector > > {}; } // namespace dispatch #endif /*! \brief Split a geometry into monotonic sections \ingroup sectionalize \tparam Geometry type of geometry to check \tparam Sections type of sections to create \param geometry geometry to create sections from \param robust_policy policy to handle robustness issues \param sections structure with sections \param envelope_strategy strategy for envelope calculation \param expand_strategy strategy for partitions \param source_index index to assign to the ring_identifiers \param max_count maximal number of points per section (defaults to 10, this seems to give the fastest results) */ template < bool Reverse, typename DimensionVector, typename Geometry, typename Sections, typename RobustPolicy, typename EnvelopeStrategy, typename ExpandStrategy > inline void sectionalize(Geometry const& geometry, RobustPolicy const& robust_policy, Sections& sections, EnvelopeStrategy const& envelope_strategy, ExpandStrategy const& expand_strategy, int source_index = 0, std::size_t max_count = 10) { BOOST_STATIC_ASSERT((! std::is_fundamental<EnvelopeStrategy>::value)); concepts::check<Geometry const>(); typedef typename boost::range_value<Sections>::type section_type; // Compiletime check for point type of section boxes // and point type related to robust policy typedef typename geometry::coordinate_type < typename section_type::box_type >::type ctype1; typedef typename geometry::coordinate_type < typename geometry::robust_point_type < typename geometry::point_type<Geometry>::type, RobustPolicy >::type >::type ctype2; BOOST_STATIC_ASSERT((std::is_same<ctype1, ctype2>::value)); sections.clear(); ring_identifier ring_id; ring_id.source_index = source_index; dispatch::sectionalize < typename tag<Geometry>::type, Geometry, Reverse, DimensionVector >::apply(geometry, robust_policy, sections, envelope_strategy, expand_strategy, ring_id, max_count); detail::sectionalize::enlarge_sections(sections, envelope_strategy); } template < bool Reverse, typename DimensionVector, typename Geometry, typename Sections, typename RobustPolicy > inline void sectionalize(Geometry const& geometry, RobustPolicy const& robust_policy, Sections& sections, int source_index = 0, std::size_t max_count = 10) { typedef typename strategy::envelope::services::default_strategy < typename tag<Geometry>::type, typename cs_tag<Geometry>::type >::type envelope_strategy_type; typedef typename strategy::expand::services::default_strategy < std::conditional_t < std::is_same<typename tag<Geometry>::type, box_tag>::value, box_tag, segment_tag >, typename cs_tag<Geometry>::type >::type expand_strategy_type; boost::geometry::sectionalize < Reverse, DimensionVector >(geometry, robust_policy, sections, envelope_strategy_type(), expand_strategy_type(), source_index, max_count); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP detail/sections/section_functions.hpp 0000644 00000012663 15125631656 0014124 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015, 2017, 2018. // Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/policies/robustness/robust_point_type.hpp> // For spherical/geographic longitudes covered_by point/box #include <boost/geometry/strategies/cartesian/point_in_box.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace section { // TODO: This code is CS-specific, should be moved to strategies template < std::size_t Dimension, typename Geometry, typename CastedCSTag = typename tag_cast < typename cs_tag<Geometry>::type, spherical_tag >::type > struct preceding_check { template <typename Point, typename Box> static inline bool apply(int dir, Point const& point, Box const& /*point_box*/, Box const& other_box) { return (dir == 1 && get<Dimension>(point) < get<min_corner, Dimension>(other_box)) || (dir == -1 && get<Dimension>(point) > get<max_corner, Dimension>(other_box)); } }; template <typename Geometry> struct preceding_check<0, Geometry, spherical_tag> { template <typename Point, typename Box> static inline bool apply(int dir, Point const& point, Box const& point_box, Box const& other_box) { typedef typename select_coordinate_type < Point, Box >::type calc_t; typedef typename coordinate_system<Point>::type::units units_t; calc_t const c0 = 0; calc_t const value = get<0>(point); calc_t const other_min = get<min_corner, 0>(other_box); calc_t const other_max = get<max_corner, 0>(other_box); bool const pt_covered = strategy::within::detail::covered_by_range < Point, 0, spherical_tag >::apply(value, other_min, other_max); if (pt_covered) { return false; } if (dir == 1) { calc_t const diff_min = math::longitude_distance_signed < units_t, calc_t >(other_min, value); calc_t const diff_min_min = math::longitude_distance_signed < units_t, calc_t >(other_min, get<min_corner, 0>(point_box)); return diff_min < c0 && diff_min_min <= c0 && diff_min_min <= diff_min; } else if (dir == -1) { calc_t const diff_max = math::longitude_distance_signed < units_t, calc_t >(other_max, value); calc_t const diff_max_max = math::longitude_distance_signed < units_t, calc_t >(other_max, get<max_corner, 0>(point_box)); return diff_max > c0 && diff_max_max >= c0 && diff_max <= diff_max_max; } return false; } }; template < std::size_t Dimension, typename Point, typename Box, typename RobustPolicy > static inline bool preceding(int dir, Point const& point, Box const& point_box, Box const& other_box, RobustPolicy const& robust_policy) { typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point; assert_coordinate_type_equal(robust_point, point_box); geometry::recalculate(robust_point, point, robust_policy); return preceding_check<Dimension, Box>::apply(dir, robust_point, point_box, other_box); } template < std::size_t Dimension, typename Point, typename Box, typename RobustPolicy > static inline bool exceeding(int dir, Point const& point, Box const& point_box, Box const& other_box, RobustPolicy const& robust_policy) { return preceding<Dimension>(-dir, point, point_box, other_box, robust_policy); } }} // namespace detail::section #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP detail/sections/range_by_section.hpp 0000644 00000012333 15125631656 0013674 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace section { template <typename Range, typename Section> struct full_section_range { static inline Range const& apply(Range const& range, Section const& ) { return range; } }; template <typename Polygon, typename Section> struct full_section_polygon { static inline typename ring_return_type<Polygon const>::type apply(Polygon const& polygon, Section const& section) { return section.ring_id.ring_index < 0 ? geometry::exterior_ring(polygon) : range::at(geometry::interior_rings(polygon), static_cast<std::size_t>(section.ring_id.ring_index)); } }; template < typename MultiGeometry, typename Section, typename Policy > struct full_section_multi { static inline typename ring_return_type<MultiGeometry const>::type apply( MultiGeometry const& multi, Section const& section) { typedef typename boost::range_size<MultiGeometry>::type size_type; BOOST_GEOMETRY_ASSERT ( section.ring_id.multi_index >= 0 && size_type(section.ring_id.multi_index) < boost::size(multi) ); return Policy::apply(range::at(multi, size_type(section.ring_id.multi_index)), section); } }; }} // namespace detail::section #endif #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Tag, typename Geometry, typename Section > struct range_by_section { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for this Geometry type.", Tag, Geometry, Section); }; template <typename LineString, typename Section> struct range_by_section<linestring_tag, LineString, Section> : detail::section::full_section_range<LineString, Section> {}; template <typename Ring, typename Section> struct range_by_section<ring_tag, Ring, Section> : detail::section::full_section_range<Ring, Section> {}; template <typename Polygon, typename Section> struct range_by_section<polygon_tag, Polygon, Section> : detail::section::full_section_polygon<Polygon, Section> {}; template <typename MultiPolygon, typename Section> struct range_by_section<multi_polygon_tag, MultiPolygon, Section> : detail::section::full_section_multi < MultiPolygon, Section, detail::section::full_section_polygon < typename boost::range_value<MultiPolygon>::type, Section > > {}; template <typename MultiLinestring, typename Section> struct range_by_section<multi_linestring_tag, MultiLinestring, Section> : detail::section::full_section_multi < MultiLinestring, Section, detail::section::full_section_range < typename boost::range_value<MultiLinestring>::type, Section > > {}; } // namespace dispatch #endif /*! \brief Get full ring (exterior, one of interiors, one from multi) indicated by the specified section \ingroup sectionalize \tparam Geometry type \tparam Section type of section to get from \param geometry geometry to take section of \param section structure with section */ template <typename Geometry, typename Section> inline typename ring_return_type<Geometry const>::type range_by_section(Geometry const& geometry, Section const& section) { concepts::check<Geometry const>(); return dispatch::range_by_section < typename tag<Geometry>::type, Geometry, Section >::apply(geometry, section); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP detail/partition.hpp 0000644 00000072303 15125631656 0010547 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2011-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP #include <cstddef> #include <type_traits> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_type.hpp> namespace boost { namespace geometry { namespace detail { namespace partition { template <typename T, bool IsIntegral = std::is_integral<T>::value> struct divide_interval { static inline T apply(T const& mi, T const& ma) { static T const two = 2; return (mi + ma) / two; } }; template <typename T> struct divide_interval<T, true> { static inline T apply(T const& mi, T const& ma) { // avoid overflow return mi / 2 + ma / 2 + (mi % 2 + ma % 2) / 2; } }; template <int Dimension, typename Box> inline void divide_box(Box const& box, Box& lower_box, Box& upper_box) { typedef typename coordinate_type<Box>::type ctype; // Divide input box into two parts, e.g. left/right ctype mid = divide_interval<ctype>::apply( geometry::get<min_corner, Dimension>(box), geometry::get<max_corner, Dimension>(box)); lower_box = box; upper_box = box; geometry::set<max_corner, Dimension>(lower_box, mid); geometry::set<min_corner, Dimension>(upper_box, mid); } // Divide forward_range into three subsets: lower, upper and oversized // (not-fitting) // (lower == left or bottom, upper == right or top) template <typename Box, typename IteratorVector, typename OverlapsPolicy> inline void divide_into_subsets(Box const& lower_box, Box const& upper_box, IteratorVector const& input, IteratorVector& lower, IteratorVector& upper, IteratorVector& exceeding, OverlapsPolicy const& overlaps_policy) { typedef typename boost::range_iterator < IteratorVector const >::type it_type; for(it_type it = boost::begin(input); it != boost::end(input); ++it) { bool const lower_overlapping = overlaps_policy.apply(lower_box, **it); bool const upper_overlapping = overlaps_policy.apply(upper_box, **it); if (lower_overlapping && upper_overlapping) { exceeding.push_back(*it); } else if (lower_overlapping) { lower.push_back(*it); } else if (upper_overlapping) { upper.push_back(*it); } else { // Is nowhere. That is (since 1.58) possible, it might be // skipped by the OverlapsPolicy to enhance performance } } } template < typename Box, typename IteratorVector, typename ExpandPolicy > inline void expand_with_elements(Box& total, IteratorVector const& input, ExpandPolicy const& expand_policy) { typedef typename boost::range_iterator<IteratorVector const>::type it_type; for(it_type it = boost::begin(input); it != boost::end(input); ++it) { expand_policy.apply(total, **it); } } // Match forward_range with itself template <typename IteratorVector, typename VisitPolicy> inline bool handle_one(IteratorVector const& input, VisitPolicy& visitor) { if (boost::empty(input)) { return true; } typedef typename boost::range_iterator<IteratorVector const>::type it_type; // Quadratic behaviour at lowest level (lowest quad, or all exceeding) for (it_type it1 = boost::begin(input); it1 != boost::end(input); ++it1) { it_type it2 = it1; for (++it2; it2 != boost::end(input); ++it2) { if (! visitor.apply(**it1, **it2)) { return false; // interrupt } } } return true; } // Match forward range 1 with forward range 2 template < typename IteratorVector1, typename IteratorVector2, typename VisitPolicy > inline bool handle_two(IteratorVector1 const& input1, IteratorVector2 const& input2, VisitPolicy& visitor) { typedef typename boost::range_iterator < IteratorVector1 const >::type iterator_type1; typedef typename boost::range_iterator < IteratorVector2 const >::type iterator_type2; if (boost::empty(input1) || boost::empty(input2)) { return true; } for(iterator_type1 it1 = boost::begin(input1); it1 != boost::end(input1); ++it1) { for(iterator_type2 it2 = boost::begin(input2); it2 != boost::end(input2); ++it2) { if (! visitor.apply(**it1, **it2)) { return false; // interrupt } } } return true; } template <typename IteratorVector> inline bool recurse_ok(IteratorVector const& input, std::size_t min_elements, std::size_t level) { return boost::size(input) >= min_elements && level < 100; } template <typename IteratorVector1, typename IteratorVector2> inline bool recurse_ok(IteratorVector1 const& input1, IteratorVector2 const& input2, std::size_t min_elements, std::size_t level) { return boost::size(input1) >= min_elements && recurse_ok(input2, min_elements, level); } template < typename IteratorVector1, typename IteratorVector2, typename IteratorVector3 > inline bool recurse_ok(IteratorVector1 const& input1, IteratorVector2 const& input2, IteratorVector3 const& input3, std::size_t min_elements, std::size_t level) { return boost::size(input1) >= min_elements && recurse_ok(input2, input3, min_elements, level); } template <int Dimension, typename Box> class partition_two_ranges; template <int Dimension, typename Box> class partition_one_range { template <typename IteratorVector, typename ExpandPolicy> static inline Box get_new_box(IteratorVector const& input, ExpandPolicy const& expand_policy) { Box box; geometry::assign_inverse(box); expand_with_elements(box, input, expand_policy); return box; } template < typename IteratorVector, typename VisitPolicy, typename ExpandPolicy, typename OverlapsPolicy, typename VisitBoxPolicy > static inline bool next_level(Box const& box, IteratorVector const& input, std::size_t level, std::size_t min_elements, VisitPolicy& visitor, ExpandPolicy const& expand_policy, OverlapsPolicy const& overlaps_policy, VisitBoxPolicy& box_policy) { if (recurse_ok(input, min_elements, level)) { return partition_one_range < 1 - Dimension, Box >::apply(box, input, level + 1, min_elements, visitor, expand_policy, overlaps_policy, box_policy); } else { return handle_one(input, visitor); } } // Function to switch to two forward ranges if there are // geometries exceeding the separation line template < typename IteratorVector, typename VisitPolicy, typename ExpandPolicy, typename OverlapsPolicy, typename VisitBoxPolicy > static inline bool next_level2(Box const& box, IteratorVector const& input1, IteratorVector const& input2, std::size_t level, std::size_t min_elements, VisitPolicy& visitor, ExpandPolicy const& expand_policy, OverlapsPolicy const& overlaps_policy, VisitBoxPolicy& box_policy) { if (recurse_ok(input1, input2, min_elements, level)) { return partition_two_ranges < 1 - Dimension, Box >::apply(box, input1, input2, level + 1, min_elements, visitor, expand_policy, overlaps_policy, expand_policy, overlaps_policy, box_policy); } else { return handle_two(input1, input2, visitor); } } public : template < typename IteratorVector, typename VisitPolicy, typename ExpandPolicy, typename OverlapsPolicy, typename VisitBoxPolicy > static inline bool apply(Box const& box, IteratorVector const& input, std::size_t level, std::size_t min_elements, VisitPolicy& visitor, ExpandPolicy const& expand_policy, OverlapsPolicy const& overlaps_policy, VisitBoxPolicy& box_policy) { box_policy.apply(box, level); Box lower_box, upper_box; divide_box<Dimension>(box, lower_box, upper_box); IteratorVector lower, upper, exceeding; divide_into_subsets(lower_box, upper_box, input, lower, upper, exceeding, overlaps_policy); if (! boost::empty(exceeding)) { // Get the box of exceeding-only Box exceeding_box = get_new_box(exceeding, expand_policy); // Recursively do exceeding elements only, in next dimension they // will probably be less exceeding within the new box if (! (next_level(exceeding_box, exceeding, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy) // Switch to two forward ranges, combine exceeding with // lower resp upper, but not lower/lower, upper/upper && next_level2(exceeding_box, exceeding, lower, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy) && next_level2(exceeding_box, exceeding, upper, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy)) ) { return false; // interrupt } } // Recursively call operation both parts return next_level(lower_box, lower, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy) && next_level(upper_box, upper, level, min_elements, visitor, expand_policy, overlaps_policy, box_policy); } }; template < int Dimension, typename Box > class partition_two_ranges { template < typename IteratorVector1, typename IteratorVector2, typename VisitPolicy, typename ExpandPolicy1, typename OverlapsPolicy1, typename ExpandPolicy2, typename OverlapsPolicy2, typename VisitBoxPolicy > static inline bool next_level(Box const& box, IteratorVector1 const& input1, IteratorVector2 const& input2, std::size_t level, std::size_t min_elements, VisitPolicy& visitor, ExpandPolicy1 const& expand_policy1, OverlapsPolicy1 const& overlaps_policy1, ExpandPolicy2 const& expand_policy2, OverlapsPolicy2 const& overlaps_policy2, VisitBoxPolicy& box_policy) { return partition_two_ranges < 1 - Dimension, Box >::apply(box, input1, input2, level + 1, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy); } template <typename IteratorVector, typename ExpandPolicy> static inline Box get_new_box(IteratorVector const& input, ExpandPolicy const& expand_policy) { Box box; geometry::assign_inverse(box); expand_with_elements(box, input, expand_policy); return box; } template < typename IteratorVector1, typename IteratorVector2, typename ExpandPolicy1, typename ExpandPolicy2 > static inline Box get_new_box(IteratorVector1 const& input1, IteratorVector2 const& input2, ExpandPolicy1 const& expand_policy1, ExpandPolicy2 const& expand_policy2) { Box box = get_new_box(input1, expand_policy1); expand_with_elements(box, input2, expand_policy2); return box; } public : template < typename IteratorVector1, typename IteratorVector2, typename VisitPolicy, typename ExpandPolicy1, typename OverlapsPolicy1, typename ExpandPolicy2, typename OverlapsPolicy2, typename VisitBoxPolicy > static inline bool apply(Box const& box, IteratorVector1 const& input1, IteratorVector2 const& input2, std::size_t level, std::size_t min_elements, VisitPolicy& visitor, ExpandPolicy1 const& expand_policy1, OverlapsPolicy1 const& overlaps_policy1, ExpandPolicy2 const& expand_policy2, OverlapsPolicy2 const& overlaps_policy2, VisitBoxPolicy& box_policy) { box_policy.apply(box, level); Box lower_box, upper_box; divide_box<Dimension>(box, lower_box, upper_box); IteratorVector1 lower1, upper1, exceeding1; IteratorVector2 lower2, upper2, exceeding2; divide_into_subsets(lower_box, upper_box, input1, lower1, upper1, exceeding1, overlaps_policy1); divide_into_subsets(lower_box, upper_box, input2, lower2, upper2, exceeding2, overlaps_policy2); if (! boost::empty(exceeding1)) { // All exceeding from 1 with 2: if (recurse_ok(exceeding1, exceeding2, min_elements, level)) { Box exceeding_box = get_new_box(exceeding1, exceeding2, expand_policy1, expand_policy2); if (! next_level(exceeding_box, exceeding1, exceeding2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy)) { return false; // interrupt } } else { if (! handle_two(exceeding1, exceeding2, visitor)) { return false; // interrupt } } // All exceeding from 1 with lower and upper of 2: // (Check sizes of all three forward ranges to avoid recurse into // the same combinations again and again) if (recurse_ok(lower2, upper2, exceeding1, min_elements, level)) { Box exceeding_box = get_new_box(exceeding1, expand_policy1); if (! (next_level(exceeding_box, exceeding1, lower2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) && next_level(exceeding_box, exceeding1, upper2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy)) ) { return false; // interrupt } } else { if (! (handle_two(exceeding1, lower2, visitor) && handle_two(exceeding1, upper2, visitor)) ) { return false; // interrupt } } } if (! boost::empty(exceeding2)) { // All exceeding from 2 with lower and upper of 1: if (recurse_ok(lower1, upper1, exceeding2, min_elements, level)) { Box exceeding_box = get_new_box(exceeding2, expand_policy2); if (! (next_level(exceeding_box, lower1, exceeding2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) && next_level(exceeding_box, upper1, exceeding2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy)) ) { return false; // interrupt } } else { if (! (handle_two(lower1, exceeding2, visitor) && handle_two(upper1, exceeding2, visitor)) ) { return false; // interrupt } } } if (recurse_ok(lower1, lower2, min_elements, level)) { if (! next_level(lower_box, lower1, lower2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) ) { return false; // interrupt } } else { if (! handle_two(lower1, lower2, visitor)) { return false; // interrupt } } if (recurse_ok(upper1, upper2, min_elements, level)) { if (! next_level(upper_box, upper1, upper2, level, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_policy) ) { return false; // interrupt } } else { if (! handle_two(upper1, upper2, visitor)) { return false; // interrupt } } return true; } }; struct visit_no_policy { template <typename Box> static inline void apply(Box const&, std::size_t ) {} }; struct include_all_policy { template <typename Item> static inline bool apply(Item const&) { return true; } }; }} // namespace detail::partition template < typename Box, typename IncludePolicy1 = detail::partition::include_all_policy, typename IncludePolicy2 = detail::partition::include_all_policy > class partition { static const std::size_t default_min_elements = 16; template < typename IncludePolicy, typename ForwardRange, typename IteratorVector, typename ExpandPolicy > static inline void expand_to_range(ForwardRange const& forward_range, Box& total, IteratorVector& iterator_vector, ExpandPolicy const& expand_policy) { for(typename boost::range_iterator<ForwardRange const>::type it = boost::begin(forward_range); it != boost::end(forward_range); ++it) { if (IncludePolicy::apply(*it)) { expand_policy.apply(total, *it); iterator_vector.push_back(it); } } } public: template < typename ForwardRange, typename VisitPolicy, typename ExpandPolicy, typename OverlapsPolicy > static inline bool apply(ForwardRange const& forward_range, VisitPolicy& visitor, ExpandPolicy const& expand_policy, OverlapsPolicy const& overlaps_policy) { return apply(forward_range, visitor, expand_policy, overlaps_policy, default_min_elements, detail::partition::visit_no_policy()); } template < typename ForwardRange, typename VisitPolicy, typename ExpandPolicy, typename OverlapsPolicy > static inline bool apply(ForwardRange const& forward_range, VisitPolicy& visitor, ExpandPolicy const& expand_policy, OverlapsPolicy const& overlaps_policy, std::size_t min_elements) { return apply(forward_range, visitor, expand_policy, overlaps_policy, min_elements, detail::partition::visit_no_policy()); } template < typename ForwardRange, typename VisitPolicy, typename ExpandPolicy, typename OverlapsPolicy, typename VisitBoxPolicy > static inline bool apply(ForwardRange const& forward_range, VisitPolicy& visitor, ExpandPolicy const& expand_policy, OverlapsPolicy const& overlaps_policy, std::size_t min_elements, VisitBoxPolicy box_visitor) { typedef typename boost::range_iterator < ForwardRange const >::type iterator_type; if (std::size_t(boost::size(forward_range)) > min_elements) { std::vector<iterator_type> iterator_vector; Box total; assign_inverse(total); expand_to_range<IncludePolicy1>(forward_range, total, iterator_vector, expand_policy); return detail::partition::partition_one_range < 0, Box >::apply(total, iterator_vector, 0, min_elements, visitor, expand_policy, overlaps_policy, box_visitor); } else { for(iterator_type it1 = boost::begin(forward_range); it1 != boost::end(forward_range); ++it1) { iterator_type it2 = it1; for(++it2; it2 != boost::end(forward_range); ++it2) { if (! visitor.apply(*it1, *it2)) { return false; // interrupt } } } } return true; } template < typename ForwardRange1, typename ForwardRange2, typename VisitPolicy, typename ExpandPolicy1, typename OverlapsPolicy1 > static inline bool apply(ForwardRange1 const& forward_range1, ForwardRange2 const& forward_range2, VisitPolicy& visitor, ExpandPolicy1 const& expand_policy1, OverlapsPolicy1 const& overlaps_policy1) { return apply(forward_range1, forward_range2, visitor, expand_policy1, overlaps_policy1, expand_policy1, overlaps_policy1, default_min_elements, detail::partition::visit_no_policy()); } template < typename ForwardRange1, typename ForwardRange2, typename VisitPolicy, typename ExpandPolicy1, typename OverlapsPolicy1, typename ExpandPolicy2, typename OverlapsPolicy2 > static inline bool apply(ForwardRange1 const& forward_range1, ForwardRange2 const& forward_range2, VisitPolicy& visitor, ExpandPolicy1 const& expand_policy1, OverlapsPolicy1 const& overlaps_policy1, ExpandPolicy2 const& expand_policy2, OverlapsPolicy2 const& overlaps_policy2) { return apply(forward_range1, forward_range2, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, default_min_elements, detail::partition::visit_no_policy()); } template < typename ForwardRange1, typename ForwardRange2, typename VisitPolicy, typename ExpandPolicy1, typename OverlapsPolicy1, typename ExpandPolicy2, typename OverlapsPolicy2 > static inline bool apply(ForwardRange1 const& forward_range1, ForwardRange2 const& forward_range2, VisitPolicy& visitor, ExpandPolicy1 const& expand_policy1, OverlapsPolicy1 const& overlaps_policy1, ExpandPolicy2 const& expand_policy2, OverlapsPolicy2 const& overlaps_policy2, std::size_t min_elements) { return apply(forward_range1, forward_range2, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, min_elements, detail::partition::visit_no_policy()); } template < typename ForwardRange1, typename ForwardRange2, typename VisitPolicy, typename ExpandPolicy1, typename OverlapsPolicy1, typename ExpandPolicy2, typename OverlapsPolicy2, typename VisitBoxPolicy > static inline bool apply(ForwardRange1 const& forward_range1, ForwardRange2 const& forward_range2, VisitPolicy& visitor, ExpandPolicy1 const& expand_policy1, OverlapsPolicy1 const& overlaps_policy1, ExpandPolicy2 const& expand_policy2, OverlapsPolicy2 const& overlaps_policy2, std::size_t min_elements, VisitBoxPolicy box_visitor) { typedef typename boost::range_iterator < ForwardRange1 const >::type iterator_type1; typedef typename boost::range_iterator < ForwardRange2 const >::type iterator_type2; if (std::size_t(boost::size(forward_range1)) > min_elements && std::size_t(boost::size(forward_range2)) > min_elements) { std::vector<iterator_type1> iterator_vector1; std::vector<iterator_type2> iterator_vector2; Box total; assign_inverse(total); expand_to_range<IncludePolicy1>(forward_range1, total, iterator_vector1, expand_policy1); expand_to_range<IncludePolicy2>(forward_range2, total, iterator_vector2, expand_policy2); return detail::partition::partition_two_ranges < 0, Box >::apply(total, iterator_vector1, iterator_vector2, 0, min_elements, visitor, expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2, box_visitor); } else { for(iterator_type1 it1 = boost::begin(forward_range1); it1 != boost::end(forward_range1); ++it1) { for(iterator_type2 it2 = boost::begin(forward_range2); it2 != boost::end(forward_range2); ++it2) { if (! visitor.apply(*it1, *it2)) { return false; // interrupt } } } } return true; } }; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP detail/multi_modify.hpp 0000644 00000003612 15125631656 0011234 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename MultiGeometry, typename Policy> struct multi_modify { static inline void apply(MultiGeometry& multi) { typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it); } } template <typename Strategy> static inline void apply(MultiGeometry& multi, Strategy const& strategy) { typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, strategy); } } }; } // namespace detail #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_HPP detail/overlaps/implementation.hpp 0000644 00000010505 15125631656 0013412 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014, 2015, 2017. // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP #include <cstddef> #include <boost/geometry/core/access.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/algorithms/detail/overlaps/interface.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlaps { template < std::size_t Dimension, std::size_t DimensionCount > struct box_box_loop { template <typename Box1, typename Box2> static inline void apply(Box1 const& b1, Box2 const& b2, bool& overlaps, bool& one_in_two, bool& two_in_one) { assert_dimension_equal<Box1, Box2>(); typedef typename coordinate_type<Box1>::type coordinate_type1; typedef typename coordinate_type<Box2>::type coordinate_type2; coordinate_type1 const& min1 = get<min_corner, Dimension>(b1); coordinate_type1 const& max1 = get<max_corner, Dimension>(b1); coordinate_type2 const& min2 = get<min_corner, Dimension>(b2); coordinate_type2 const& max2 = get<max_corner, Dimension>(b2); // We might use the (not yet accepted) Boost.Interval // submission in the future // If: // B1: |-------| // B2: |------| // in any dimension -> no overlap if (max1 <= min2 || min1 >= max2) { overlaps = false; return; } // If: // B1: |--------------------| // B2: |-------------| // in all dimensions -> within, then no overlap // B1: |--------------------| // B2: |-------------| // this is "within-touch" -> then no overlap. So use < and > if (min1 < min2 || max1 > max2) { one_in_two = false; } // Same other way round if (min2 < min1 || max2 > max1) { two_in_one = false; } box_box_loop < Dimension + 1, DimensionCount >::apply(b1, b2, overlaps, one_in_two, two_in_one); } }; template < std::size_t DimensionCount > struct box_box_loop<DimensionCount, DimensionCount> { template <typename Box1, typename Box2> static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&) { } }; struct box_box { template <typename Box1, typename Box2, typename Strategy> static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/) { bool overlaps = true; bool within1 = true; bool within2 = true; box_box_loop < 0, dimension<Box1>::type::value >::apply(b1, b2, overlaps, within1, within2); /* \see http://docs.codehaus.org/display/GEOTDOC/02+Geometry+Relationships#02GeometryRelationships-Overlaps where is stated that "inside" is not an "overlap", this is true and is implemented as such. */ return overlaps && ! within1 && ! within2; } }; }} // namespace detail::overlaps #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Box1, typename Box2> struct overlaps<Box1, Box2, box_tag, box_tag> : detail::overlaps::box_box {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP detail/overlaps/interface.hpp 0000644 00000006544 15125631656 0012335 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014, 2015, 2017. // Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP #include <cstddef> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/strategies/relate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > struct overlaps : detail::relate::relate_impl < detail::de9im::static_mask_overlaps_type, Geometry1, Geometry2 > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief \brief_check2{overlap} \ingroup overlaps \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Overlaps} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{overlaps} \return \return_check2{overlap} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/overlaps.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return dispatch::overlaps < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief \brief_check2{overlap} \ingroup overlaps \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{overlap} \qbk{[include reference/algorithms/overlaps.qbk]} \qbk{ [heading Examples] [overlaps] [overlaps_output] } */ template <typename Geometry1, typename Geometry2> inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return dispatch::overlaps < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy_type()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP detail/expand/implementation.hpp 0000644 00000002243 15125631656 0013036 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015. // Modifications copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/expand/point.hpp> #include <boost/geometry/algorithms/detail/expand/segment.hpp> #include <boost/geometry/algorithms/detail/expand/box.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_IMPLEMENTATION_HPP detail/expand/box.hpp 0000644 00000003435 15125631656 0010605 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_BOX_HPP #include <boost/geometry/algorithms/dispatch/expand.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Box + box -> new box containing two input boxes template < typename BoxOut, typename BoxIn > struct expand < BoxOut, BoxIn, box_tag, box_tag > { template <typename Strategy> static inline void apply(BoxOut& box_out, BoxIn const& box_in, Strategy const& strategy) { // strategy.expand(box_out, box_in).apply(box_out, box_in); using strategy_t = decltype(strategy.expand(box_out, box_in)); strategy_t::apply(box_out, box_in); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP detail/expand/indexed.hpp 0000644 00000006365 15125631656 0011442 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015, 2016, 2017, 2018. // Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP #include <cstddef> #include <functional> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/algorithms/dispatch/expand.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace expand { template < std::size_t Index, std::size_t Dimension, std::size_t DimensionCount > struct indexed_loop { template <typename Box, typename Geometry> static inline void apply(Box& box, Geometry const& source) { typedef typename select_coordinate_type < Box, Geometry >::type coordinate_type; coordinate_type const coord = get<Index, Dimension>(source); std::less<coordinate_type> less; std::greater<coordinate_type> greater; if (less(coord, get<min_corner, Dimension>(box))) { set<min_corner, Dimension>(box, coord); } if (greater(coord, get<max_corner, Dimension>(box))) { set<max_corner, Dimension>(box, coord); } indexed_loop < Index, Dimension + 1, DimensionCount >::apply(box, source); } }; template <std::size_t Index, std::size_t DimensionCount> struct indexed_loop < Index, DimensionCount, DimensionCount > { template <typename Box, typename Geometry> static inline void apply(Box&, Geometry const&) {} }; // Changes a box such that the other box is also contained by the box template <std::size_t Dimension, std::size_t DimensionCount> struct expand_indexed { template <typename Box, typename Geometry> static inline void apply(Box& box, Geometry const& geometry) { indexed_loop < 0, Dimension, DimensionCount >::apply(box, geometry); indexed_loop < 1, Dimension, DimensionCount >::apply(box, geometry); } }; }} // namespace detail::expand #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INDEXED_HPP detail/expand/interface.hpp 0000644 00000015176 15125631656 0011762 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/dispatch/expand.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/detail.hpp> #include <boost/geometry/strategies/expand/services.hpp> #include <boost/geometry/strategy/expand.hpp> namespace boost { namespace geometry { namespace resolve_strategy { template < typename Strategy, bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value > struct expand { template <typename Box, typename Geometry> static inline void apply(Box& box, Geometry const& geometry, Strategy const& strategy) { dispatch::expand<Box, Geometry>::apply(box, geometry, strategy); } }; template <typename Strategy> struct expand<Strategy, false> { template <typename Box, typename Geometry> static inline void apply(Box& box, Geometry const& geometry, Strategy const& strategy) { using strategies::expand::services::strategy_converter; dispatch::expand < Box, Geometry >::apply(box, geometry, strategy_converter<Strategy>::get(strategy)); } }; template <> struct expand<default_strategy, false> { template <typename Box, typename Geometry> static inline void apply(Box& box, Geometry const& geometry, default_strategy) { typedef typename strategies::expand::services::default_strategy < Box, Geometry >::type strategy_type; dispatch::expand<Box, Geometry>::apply(box, geometry, strategy_type()); } }; } //namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct expand { template <typename Box, typename Strategy> static inline void apply(Box& box, Geometry const& geometry, Strategy const& strategy) { concepts::check<Box>(); concepts::check<Geometry const>(); concepts::check_concepts_and_equal_dimensions<Box, Geometry const>(); resolve_strategy::expand<Strategy>::apply(box, geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct expand<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Box, typename Strategy> struct visitor: boost::static_visitor<void> { Box& m_box; Strategy const& m_strategy; visitor(Box& box, Strategy const& strategy) : m_box(box) , m_strategy(strategy) {} template <typename Geometry> void operator()(Geometry const& geometry) const { return expand<Geometry>::apply(m_box, geometry, m_strategy); } }; template <class Box, typename Strategy> static inline void apply(Box& box, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Strategy const& strategy) { return boost::apply_visitor(visitor<Box, Strategy>(box, strategy), geometry); } }; } // namespace resolve_variant /*** *! \brief Expands a box using the extend (envelope) of another geometry (box, point) \ingroup expand \tparam Box type of the box \tparam Geometry of second geometry, to be expanded with the box \param box box to expand another geometry with, might be changed \param geometry other geometry \param strategy_less \param strategy_greater \note Strategy is currently ignored * template < typename Box, typename Geometry, typename StrategyLess, typename StrategyGreater > inline void expand(Box& box, Geometry const& geometry, StrategyLess const& strategy_less, StrategyGreater const& strategy_greater) { concepts::check_concepts_and_equal_dimensions<Box, Geometry const>(); dispatch::expand<Box, Geometry>::apply(box, geometry); } ***/ /*! \brief Expands (with strategy) \ingroup expand \tparam Box type of the box \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{expand} \param box box to be expanded using another geometry, mutable \param geometry \param_geometry geometry which envelope (bounding box) \param strategy \param_strategy{expand} will be added to the box \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/expand.qbk]} */ template <typename Box, typename Geometry, typename Strategy> inline void expand(Box& box, Geometry const& geometry, Strategy const& strategy) { resolve_variant::expand<Geometry>::apply(box, geometry, strategy); } /*! \brief Expands a box using the bounding box (envelope) of another geometry (box, point) \ingroup expand \tparam Box type of the box \tparam Geometry \tparam_geometry \param box box to be expanded using another geometry, mutable \param geometry \param_geometry geometry which envelope (bounding box) will be added to the box \qbk{[include reference/algorithms/expand.qbk]} */ template <typename Box, typename Geometry> inline void expand(Box& box, Geometry const& geometry) { resolve_variant::expand<Geometry>::apply(box, geometry, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_INTERFACE_HPP detail/expand/segment.hpp 0000644 00000003234 15125631656 0011454 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/dispatch/expand.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Box, typename Segment > struct expand < Box, Segment, box_tag, segment_tag > { template <typename Strategy> static inline void apply(Box& box, Segment const& segment, Strategy const& strategy) { strategy.expand(box, segment).apply(box, segment); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_SEGMENT_HPP detail/expand/point.hpp 0000644 00000003636 15125631656 0011151 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP #include <boost/geometry/algorithms/dispatch/expand.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Box + point -> new box containing also point template < typename BoxOut, typename Point > struct expand < BoxOut, Point, box_tag, point_tag > { template <typename Strategy> static inline void apply(BoxOut& box, Point const& point, Strategy const& strategy) { // strategy.expand(box, point).apply(box, point); using strategy_t = decltype(strategy.expand(box, point)); strategy_t::apply(box, point); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_POINT_HPP detail/assign_indexed_point.hpp 0000644 00000005140 15125631656 0012726 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP #include <cstddef> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/assign_values.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { /*! \brief Assign a box or segment with the value of a point \ingroup assign \tparam Index indicates which box-corner, min_corner (0) or max_corner (1) or which point of segment (0/1) \tparam Point \tparam_point \tparam Geometry \tparam_box_or_segment \param point \param_point \param geometry \param_box_or_segment \qbk{ [heading Example] [assign_point_to_index] [assign_point_to_index_output] } */ template <std::size_t Index, typename Geometry, typename Point> inline void assign_point_to_index(Point const& point, Geometry& geometry) { concepts::check<Point const>(); concepts::check<Geometry>(); detail::assign::assign_point_to_index < Geometry, Point, Index, 0, dimension<Geometry>::type::value >::apply(point, geometry); } /*! \brief Assign a point with a point of a box or segment \ingroup assign \tparam Index indicates which box-corner, min_corner (0) or max_corner (1) or which point of segment (0/1) \tparam Geometry \tparam_box_or_segment \tparam Point \tparam_point \param geometry \param_box_or_segment \param point \param_point \qbk{ [heading Example] [assign_point_from_index] [assign_point_from_index_output] } */ template <std::size_t Index, typename Point, typename Geometry> inline void assign_point_from_index(Geometry const& geometry, Point& point) { concepts::check<Geometry const>(); concepts::check<Point>(); detail::assign::assign_point_from_index < Geometry, Point, Index, 0, dimension<Geometry>::type::value >::apply(geometry, point); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP detail/distance/range_to_geometry_rtree.hpp 0000644 00000007632 15125631656 0015245 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP #include <iterator> #include <utility> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/iterators/has_one_element.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp> #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> #include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template < typename PointOrSegmentIterator, typename Geometry, typename Strategy > class point_or_segment_range_to_geometry_rtree { private: typedef typename std::iterator_traits < PointOrSegmentIterator >::value_type point_or_segment_type; typedef iterator_selector<Geometry const> selector_type; typedef detail::closest_feature::range_to_range_rtree range_to_range; public: typedef typename strategy::distance::services::return_type < Strategy, typename point_type<point_or_segment_type>::type, typename point_type<Geometry>::type >::type return_type; static inline return_type apply(PointOrSegmentIterator first, PointOrSegmentIterator last, Geometry const& geometry, Strategy const& strategy) { namespace sds = strategy::distance::services; BOOST_GEOMETRY_ASSERT( first != last ); if ( geometry::has_one_element(first, last) ) { return dispatch::distance < point_or_segment_type, Geometry, Strategy >::apply(*first, geometry, strategy); } typename sds::return_type < typename sds::comparable_type<Strategy>::type, typename point_type<point_or_segment_type>::type, typename point_type<Geometry>::type >::type cd_min; std::pair < point_or_segment_type, typename selector_type::iterator_type > closest_features = range_to_range::apply(first, last, selector_type::begin(geometry), selector_type::end(geometry), sds::get_comparable < Strategy >::apply(strategy), cd_min); return is_comparable<Strategy>::value ? cd_min : dispatch::distance < point_or_segment_type, typename std::iterator_traits < typename selector_type::iterator_type >::value_type, Strategy >::apply(closest_features.first, *closest_features.second, strategy); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP detail/distance/point_to_geometry.hpp 0000644 00000037200 15125631656 0014073 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP #include <iterator> #include <type_traits> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> #include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp> #include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template <typename P1, typename P2, typename Strategy> struct point_to_point { static inline typename strategy::distance::services::return_type<Strategy, P1, P2>::type apply(P1 const& p1, P2 const& p2, Strategy const& strategy) { boost::ignore_unused(strategy); return strategy.apply(p1, p2); } }; template < typename Point, typename Range, closure_selector Closure, typename Strategy > class point_to_range { private: typedef typename strategy::distance::services::comparable_type < Strategy >::type comparable_strategy; typedef detail::closest_feature::point_to_point_range < Point, Range, Closure, comparable_strategy > point_to_point_range; public: typedef typename strategy::distance::services::return_type < Strategy, Point, typename boost::range_value<Range>::type >::type return_type; static inline return_type apply(Point const& point, Range const& range, Strategy const& strategy) { return_type const zero = return_type(0); if (boost::size(range) == 0) { return zero; } namespace sds = strategy::distance::services; typename sds::return_type < comparable_strategy, Point, typename point_type<Range>::type >::type cd_min; std::pair < typename boost::range_iterator<Range const>::type, typename boost::range_iterator<Range const>::type > it_pair = point_to_point_range::apply(point, boost::begin(range), boost::end(range), sds::get_comparable < Strategy >::apply(strategy), cd_min); return is_comparable<Strategy>::value ? cd_min : strategy.apply(point, *it_pair.first, *it_pair.second); } }; template < typename Point, typename Ring, closure_selector Closure, typename Strategy > struct point_to_ring { typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Ring>::type >::type return_type; static inline return_type apply(Point const& point, Ring const& ring, Strategy const& strategy) { // TODO: pass strategy if (within::within_point_geometry(point, ring, strategy.get_point_in_geometry_strategy())) { return return_type(0); } return point_to_range < Point, Ring, closure<Ring>::value, Strategy >::apply(point, ring, strategy); } }; template < typename Point, typename Polygon, closure_selector Closure, typename Strategy > class point_to_polygon { public: typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Polygon>::type >::type return_type; private: typedef point_to_range < Point, typename ring_type<Polygon>::type, Closure, Strategy > per_ring; struct distance_to_interior_rings { template <typename InteriorRingIterator> static inline return_type apply(Point const& point, InteriorRingIterator first, InteriorRingIterator last, Strategy const& strategy) { for (InteriorRingIterator it = first; it != last; ++it) { // TODO: pass strategy if (within::within_point_geometry(point, *it, strategy.get_point_in_geometry_strategy())) { // the point is inside a polygon hole, so its distance // to the polygon its distance to the polygon's // hole boundary return per_ring::apply(point, *it, strategy); } } return 0; } template <typename InteriorRings> static inline return_type apply(Point const& point, InteriorRings const& interior_rings, Strategy const& strategy) { return apply(point, boost::begin(interior_rings), boost::end(interior_rings), strategy); } }; public: static inline return_type apply(Point const& point, Polygon const& polygon, Strategy const& strategy) { // TODO: pass strategy if (! within::covered_by_point_geometry(point, exterior_ring(polygon), strategy.get_point_in_geometry_strategy())) { // the point is outside the exterior ring, so its distance // to the polygon is its distance to the polygon's exterior ring return per_ring::apply(point, exterior_ring(polygon), strategy); } // Check interior rings return distance_to_interior_rings::apply(point, interior_rings(polygon), strategy); } }; template < typename Point, typename MultiGeometry, typename Strategy, bool CheckCoveredBy = std::is_same < typename tag<MultiGeometry>::type, multi_polygon_tag >::value > class point_to_multigeometry { private: typedef detail::closest_feature::geometry_to_range geometry_to_range; public: typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<MultiGeometry>::type >::type return_type; static inline return_type apply(Point const& point, MultiGeometry const& multigeometry, Strategy const& strategy) { typedef iterator_selector<MultiGeometry const> selector_type; namespace sds = strategy::distance::services; typename sds::return_type < typename sds::comparable_type<Strategy>::type, Point, typename point_type<MultiGeometry>::type >::type cd; typename selector_type::iterator_type it_min = geometry_to_range::apply(point, selector_type::begin(multigeometry), selector_type::end(multigeometry), sds::get_comparable < Strategy >::apply(strategy), cd); return is_comparable<Strategy>::value ? cd : dispatch::distance < Point, typename std::iterator_traits < typename selector_type::iterator_type >::value_type, Strategy >::apply(point, *it_min, strategy); } }; // this is called only for multipolygons, hence the change in the // template parameter name MultiGeometry to MultiPolygon template <typename Point, typename MultiPolygon, typename Strategy> struct point_to_multigeometry<Point, MultiPolygon, Strategy, true> { typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<MultiPolygon>::type >::type return_type; static inline return_type apply(Point const& point, MultiPolygon const& multipolygon, Strategy const& strategy) { // TODO: pass strategy if (within::covered_by_point_geometry(point, multipolygon, strategy.get_point_in_geometry_strategy())) { return 0; } return point_to_multigeometry < Point, MultiPolygon, Strategy, false >::apply(point, multipolygon, strategy); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Point-point template <typename P1, typename P2, typename Strategy> struct distance < P1, P2, Strategy, point_tag, point_tag, strategy_tag_distance_point_point, false > : detail::distance::point_to_point<P1, P2, Strategy> {}; // Point-line version 2, where point-segment strategy is specified template <typename Point, typename Linestring, typename Strategy> struct distance < Point, Linestring, Strategy, point_tag, linestring_tag, strategy_tag_distance_point_segment, false > : detail::distance::point_to_range<Point, Linestring, closed, Strategy> {}; // Point-ring , where point-segment strategy is specified template <typename Point, typename Ring, typename Strategy> struct distance < Point, Ring, Strategy, point_tag, ring_tag, strategy_tag_distance_point_segment, false > : detail::distance::point_to_ring < Point, Ring, closure<Ring>::value, Strategy > {}; // Point-polygon , where point-segment strategy is specified template <typename Point, typename Polygon, typename Strategy> struct distance < Point, Polygon, Strategy, point_tag, polygon_tag, strategy_tag_distance_point_segment, false > : detail::distance::point_to_polygon < Point, Polygon, closure<Polygon>::value, Strategy > {}; // Point-segment version 2, with point-segment strategy template <typename Point, typename Segment, typename Strategy> struct distance < Point, Segment, Strategy, point_tag, segment_tag, strategy_tag_distance_point_segment, false > { static inline typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Segment>::type >::type apply(Point const& point, Segment const& segment, Strategy const& strategy) { typename point_type<Segment>::type p[2]; geometry::detail::assign_point_from_index<0>(segment, p[0]); geometry::detail::assign_point_from_index<1>(segment, p[1]); boost::ignore_unused(strategy); return strategy.apply(point, p[0], p[1]); } }; template <typename Point, typename Box, typename Strategy> struct distance < Point, Box, Strategy, point_tag, box_tag, strategy_tag_distance_point_box, false > { static inline typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Box>::type >::type apply(Point const& point, Box const& box, Strategy const& strategy) { boost::ignore_unused(strategy); return strategy.apply(point, box); } }; template<typename Point, typename MultiPoint, typename Strategy> struct distance < Point, MultiPoint, Strategy, point_tag, multi_point_tag, strategy_tag_distance_point_point, false > : detail::distance::point_to_multigeometry < Point, MultiPoint, Strategy > {}; template<typename Point, typename MultiLinestring, typename Strategy> struct distance < Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag, strategy_tag_distance_point_segment, false > : detail::distance::point_to_multigeometry < Point, MultiLinestring, Strategy > {}; template<typename Point, typename MultiPolygon, typename Strategy> struct distance < Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag, strategy_tag_distance_point_segment, false > : detail::distance::point_to_multigeometry < Point, MultiPolygon, Strategy > {}; template <typename Point, typename Linear, typename Strategy> struct distance < Point, Linear, Strategy, point_tag, linear_tag, strategy_tag_distance_point_segment, false > : distance < Point, Linear, Strategy, point_tag, typename tag<Linear>::type, strategy_tag_distance_point_segment, false > {}; template <typename Point, typename Areal, typename Strategy> struct distance < Point, Areal, Strategy, point_tag, areal_tag, strategy_tag_distance_point_segment, false > : distance < Point, Areal, Strategy, point_tag, typename tag<Areal>::type, strategy_tag_distance_point_segment, false > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP detail/distance/is_comparable.hpp 0000644 00000002207 15125631656 0013124 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP #define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP #include <type_traits> #include <boost/geometry/strategies/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { // metafunction to determine is a strategy is comparable or not template <typename Strategy> struct is_comparable : std::is_same < Strategy, typename strategy::distance::services::comparable_type < Strategy >::type > {}; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP detail/distance/segment_to_box.hpp 0000644 00000072363 15125631656 0013352 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP #include <cstddef> #include <functional> #include <type_traits> #include <vector> #include <boost/core/ignore_unused.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/util/calculation_type.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/has_nan_coordinate.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/strategies/disjoint.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { // TODO: Take strategy template <typename Segment, typename Box> inline bool intersects_segment_box(Segment const& segment, Box const& box) { typedef typename strategy::disjoint::services::default_strategy < Segment, Box >::type strategy_type; return ! detail::disjoint::disjoint_segment_box::apply(segment, box, strategy_type()); } template < typename Segment, typename Box, typename Strategy, bool UsePointBoxStrategy = false > class segment_to_box_2D_generic { private: typedef typename point_type<Segment>::type segment_point; typedef typename point_type<Box>::type box_point; typedef typename strategy::distance::services::comparable_type < typename Strategy::distance_ps_strategy::type >::type comparable_strategy; typedef detail::closest_feature::point_to_point_range < segment_point, std::vector<box_point>, open, comparable_strategy > point_to_point_range; typedef typename strategy::distance::services::return_type < comparable_strategy, segment_point, box_point >::type comparable_return_type; public: typedef typename strategy::distance::services::return_type < Strategy, segment_point, box_point >::type return_type; static inline return_type apply(Segment const& segment, Box const& box, Strategy const& strategy, bool check_intersection = true) { if (check_intersection && intersects_segment_box(segment, box)) { return 0; } comparable_strategy cstrategy = strategy::distance::services::get_comparable < typename Strategy::distance_ps_strategy::type >::apply(strategy.get_distance_ps_strategy()); // get segment points segment_point p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); // get box points std::vector<box_point> box_points(4); detail::assign_box_corners_oriented<true>(box, box_points); comparable_return_type cd[6]; for (unsigned int i = 0; i < 4; ++i) { cd[i] = cstrategy.apply(box_points[i], p[0], p[1]); } std::pair < typename std::vector<box_point>::const_iterator, typename std::vector<box_point>::const_iterator > bit_min[2]; bit_min[0] = point_to_point_range::apply(p[0], box_points.begin(), box_points.end(), cstrategy, cd[4]); bit_min[1] = point_to_point_range::apply(p[1], box_points.begin(), box_points.end(), cstrategy, cd[5]); unsigned int imin = 0; for (unsigned int i = 1; i < 6; ++i) { if (cd[i] < cd[imin]) { imin = i; } } if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) { return cd[imin]; } if (imin < 4) { return strategy.get_distance_ps_strategy().apply(box_points[imin], p[0], p[1]); } else { unsigned int bimin = imin - 4; return strategy.get_distance_ps_strategy().apply(p[bimin], *bit_min[bimin].first, *bit_min[bimin].second); } } }; template < typename Segment, typename Box, typename Strategy > class segment_to_box_2D_generic<Segment, Box, Strategy, true> { private: typedef typename point_type<Segment>::type segment_point; typedef typename point_type<Box>::type box_point; typedef typename strategy::distance::services::comparable_type < Strategy >::type comparable_strategy; typedef typename strategy::distance::services::return_type < comparable_strategy, segment_point, box_point >::type comparable_return_type; typedef typename detail::distance::default_strategy < segment_point, Box >::type point_box_strategy; typedef typename strategy::distance::services::comparable_type < point_box_strategy >::type point_box_comparable_strategy; public: typedef typename strategy::distance::services::return_type < Strategy, segment_point, box_point >::type return_type; static inline return_type apply(Segment const& segment, Box const& box, Strategy const& strategy, bool check_intersection = true) { if (check_intersection && intersects_segment_box(segment, box)) { return 0; } comparable_strategy cstrategy = strategy::distance::services::get_comparable < Strategy >::apply(strategy); boost::ignore_unused(cstrategy); // get segment points segment_point p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); // get box points std::vector<box_point> box_points(4); detail::assign_box_corners_oriented<true>(box, box_points); comparable_return_type cd[6]; for (unsigned int i = 0; i < 4; ++i) { cd[i] = cstrategy.apply(box_points[i], p[0], p[1]); } point_box_comparable_strategy pb_cstrategy; boost::ignore_unused(pb_cstrategy); cd[4] = pb_cstrategy.apply(p[0], box); cd[5] = pb_cstrategy.apply(p[1], box); unsigned int imin = 0; for (unsigned int i = 1; i < 6; ++i) { if (cd[i] < cd[imin]) { imin = i; } } if (is_comparable<Strategy>::value) { return cd[imin]; } if (imin < 4) { strategy.apply(box_points[imin], p[0], p[1]); } else { return point_box_strategy().apply(p[imin - 4], box); } } }; template < typename ReturnType, typename SegmentPoint, typename BoxPoint, typename SBStrategy > class segment_to_box_2D { private: template <typename Result> struct cast_to_result { template <typename T> static inline Result apply(T const& t) { return boost::numeric_cast<Result>(t); } }; template <typename T, bool IsLess /* true */> struct compare_less_equal { typedef compare_less_equal<T, !IsLess> other; template <typename T1, typename T2> inline bool operator()(T1 const& t1, T2 const& t2) const { return std::less_equal<T>()(cast_to_result<T>::apply(t1), cast_to_result<T>::apply(t2)); } }; template <typename T> struct compare_less_equal<T, false> { typedef compare_less_equal<T, true> other; template <typename T1, typename T2> inline bool operator()(T1 const& t1, T2 const& t2) const { return std::greater_equal<T>()(cast_to_result<T>::apply(t1), cast_to_result<T>::apply(t2)); } }; template <typename LessEqual> struct other_compare { typedef typename LessEqual::other type; }; // it is assumed here that p0 lies to the right of the box (so the // entire segment lies to the right of the box) template <typename LessEqual> struct right_of_box { static inline ReturnType apply(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& bottom_right, BoxPoint const& top_right, SBStrategy const& sb_strategy) { boost::ignore_unused(sb_strategy); // the implementation below is written for non-negative slope // segments // // for negative slope segments swap the roles of bottom_right // and top_right and use greater_equal instead of less_equal. typedef cast_to_result<ReturnType> cast; LessEqual less_equal; typename SBStrategy::distance_ps_strategy::type ps_strategy = sb_strategy.get_distance_ps_strategy(); if (less_equal(geometry::get<1>(bottom_right), geometry::get<1>(p0))) { //if p0 is in box's band if (less_equal(geometry::get<1>(p0), geometry::get<1>(top_right))) { // segment & crosses band (TODO:merge with box-box dist) if (math::equals(geometry::get<0>(p0), geometry::get<0>(p1))) { SegmentPoint high = geometry::get<1>(p1) > geometry::get<1>(p0) ? p1 : p0; if (less_equal(geometry::get<1>(high), geometry::get<1>(top_right))) { return cast::apply(ps_strategy.apply(high, bottom_right, top_right)); } return cast::apply(ps_strategy.apply(top_right, p0, p1)); } return cast::apply(ps_strategy.apply(p0, bottom_right, top_right)); } // distance is realized between the top-right // corner of the box and the segment return cast::apply(ps_strategy.apply(top_right, p0, p1)); } else { // distance is realized between the bottom-right // corner of the box and the segment return cast::apply(ps_strategy.apply(bottom_right, p0, p1)); } } }; // it is assumed here that p0 lies above the box (so the // entire segment lies above the box) template <typename LessEqual> struct above_of_box { static inline ReturnType apply(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, SBStrategy const& sb_strategy) { boost::ignore_unused(sb_strategy); return apply(p0, p1, p0, top_left, sb_strategy); } static inline ReturnType apply(SegmentPoint const& p0, SegmentPoint const& p1, SegmentPoint const& p_max, BoxPoint const& top_left, SBStrategy const& sb_strategy) { boost::ignore_unused(sb_strategy); typedef cast_to_result<ReturnType> cast; LessEqual less_equal; // p0 is above the upper segment of the box (and inside its band) // then compute the vertical (i.e. meridian for spherical) distance if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p_max))) { ReturnType diff = sb_strategy.get_distance_ps_strategy().vertical_or_meridian( geometry::get_as_radian<1>(p_max), geometry::get_as_radian<1>(top_left)); return strategy::distance::services::result_from_distance < SBStrategy, SegmentPoint, BoxPoint >::apply(sb_strategy, math::abs(diff)); } // p0 is to the left of the box, but p1 is above the box // in this case the distance is realized between the // top-left corner of the box and the segment return cast::apply(sb_strategy.get_distance_ps_strategy(). apply(top_left, p0, p1)); } }; template <typename LessEqual> struct check_right_left_of_box { static inline bool apply(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right, SBStrategy const& sb_strategy, ReturnType& result) { // p0 lies to the right of the box if (geometry::get<0>(p0) >= geometry::get<0>(top_right)) { result = right_of_box < LessEqual >::apply(p0, p1, bottom_right, top_right, sb_strategy); return true; } // p1 lies to the left of the box if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left)) { result = right_of_box < typename other_compare<LessEqual>::type >::apply(p1, p0, top_left, bottom_left, sb_strategy); return true; } return false; } }; template <typename LessEqual> struct check_above_below_of_box { static inline bool apply(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right, SBStrategy const& sb_strategy, ReturnType& result) { typedef compare_less_equal<ReturnType, false> GreaterEqual; // the segment lies below the box if (geometry::get<1>(p1) < geometry::get<1>(bottom_left)) { result = sb_strategy.template segment_below_of_box < LessEqual, ReturnType >(p0, p1, top_left, top_right, bottom_left, bottom_right); return true; } // the segment lies above the box if (geometry::get<1>(p0) > geometry::get<1>(top_right)) { result = (std::min)(above_of_box < LessEqual >::apply(p0, p1, top_left, sb_strategy), above_of_box < GreaterEqual >::apply(p1, p0, top_right, sb_strategy)); return true; } return false; } }; struct check_generic_position { static inline bool apply(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& corner1, BoxPoint const& corner2, SBStrategy const& sb_strategy, ReturnType& result) { typename SBStrategy::side_strategy_type side_strategy = sb_strategy.get_side_strategy(); typedef cast_to_result<ReturnType> cast; ReturnType diff1 = cast::apply(geometry::get<1>(p1)) - cast::apply(geometry::get<1>(p0)); typename SBStrategy::distance_ps_strategy::type ps_strategy = sb_strategy.get_distance_ps_strategy(); int sign = diff1 < 0 ? -1 : 1; if (side_strategy.apply(p0, p1, corner1) * sign < 0) { result = cast::apply(ps_strategy.apply(corner1, p0, p1)); return true; } if (side_strategy.apply(p0, p1, corner2) * sign > 0) { result = cast::apply(ps_strategy.apply(corner2, p0, p1)); return true; } return false; } }; static inline ReturnType non_negative_slope_segment(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right, SBStrategy const& sb_strategy) { typedef compare_less_equal<ReturnType, true> less_equal; // assert that the segment has non-negative slope BOOST_GEOMETRY_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1)) && geometry::get<1>(p0) < geometry::get<1>(p1)) || ( geometry::get<0>(p0) < geometry::get<0>(p1) && geometry::get<1>(p0) <= geometry::get<1>(p1) ) || geometry::has_nan_coordinate(p0) || geometry::has_nan_coordinate(p1)); ReturnType result(0); if (check_right_left_of_box < less_equal >::apply(p0, p1, top_left, top_right, bottom_left, bottom_right, sb_strategy, result)) { return result; } if (check_above_below_of_box < less_equal >::apply(p0, p1, top_left, top_right, bottom_left, bottom_right, sb_strategy, result)) { return result; } if (check_generic_position::apply(p0, p1, top_left, bottom_right, sb_strategy, result)) { return result; } // in all other cases the box and segment intersect, so return 0 return result; } static inline ReturnType negative_slope_segment(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right, SBStrategy const& sb_strategy) { typedef compare_less_equal<ReturnType, false> greater_equal; // assert that the segment has negative slope BOOST_GEOMETRY_ASSERT( ( geometry::get<0>(p0) < geometry::get<0>(p1) && geometry::get<1>(p0) > geometry::get<1>(p1) ) || geometry::has_nan_coordinate(p0) || geometry::has_nan_coordinate(p1) ); ReturnType result(0); if (check_right_left_of_box < greater_equal >::apply(p0, p1, bottom_left, bottom_right, top_left, top_right, sb_strategy, result)) { return result; } if (check_above_below_of_box < greater_equal >::apply(p1, p0, top_right, top_left, bottom_right, bottom_left, sb_strategy, result)) { return result; } if (check_generic_position::apply(p0, p1, bottom_left, top_right, sb_strategy, result)) { return result; } // in all other cases the box and segment intersect, so return 0 return result; } public: static inline ReturnType apply(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, BoxPoint const& top_right, BoxPoint const& bottom_left, BoxPoint const& bottom_right, SBStrategy const& sb_strategy) { BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, typename SBStrategy::cs_tag>()(p0, p1)) || geometry::has_nan_coordinate(p0) || geometry::has_nan_coordinate(p1) ); if (geometry::get<0>(p0) < geometry::get<0>(p1) && geometry::get<1>(p0) > geometry::get<1>(p1)) { return negative_slope_segment(p0, p1, top_left, top_right, bottom_left, bottom_right, sb_strategy); } return non_negative_slope_segment(p0, p1, top_left, top_right, bottom_left, bottom_right, sb_strategy); } template <typename LessEqual> static inline ReturnType call_above_of_box(SegmentPoint const& p0, SegmentPoint const& p1, SegmentPoint const& p_max, BoxPoint const& top_left, SBStrategy const& sb_strategy) { return above_of_box<LessEqual>::apply(p0, p1, p_max, top_left, sb_strategy); } template <typename LessEqual> static inline ReturnType call_above_of_box(SegmentPoint const& p0, SegmentPoint const& p1, BoxPoint const& top_left, SBStrategy const& sb_strategy) { return above_of_box<LessEqual>::apply(p0, p1, top_left, sb_strategy); } }; //========================================================================= template < typename Segment, typename Box, typename std::size_t Dimension, typename SBStrategy > class segment_to_box : not_implemented<Segment, Box> {}; template < typename Segment, typename Box, typename SBStrategy > class segment_to_box<Segment, Box, 2, SBStrategy> { private: typedef typename point_type<Segment>::type segment_point; typedef typename point_type<Box>::type box_point; typedef typename strategy::distance::services::comparable_type < SBStrategy >::type ps_comparable_strategy; typedef typename strategy::distance::services::return_type < ps_comparable_strategy, segment_point, box_point >::type comparable_return_type; public: typedef typename strategy::distance::services::return_type < SBStrategy, segment_point, box_point >::type return_type; static inline return_type apply(Segment const& segment, Box const& box, SBStrategy const& sb_strategy) { segment_point p[2]; detail::assign_point_from_index<0>(segment, p[0]); detail::assign_point_from_index<1>(segment, p[1]); if (detail::equals::equals_point_point(p[0], p[1], sb_strategy.get_equals_point_point_strategy())) { typedef std::conditional_t < std::is_same < ps_comparable_strategy, SBStrategy >::value, typename strategy::distance::services::comparable_type < typename SBStrategy::distance_pb_strategy::type >::type, typename SBStrategy::distance_pb_strategy::type > point_box_strategy_type; return dispatch::distance < segment_point, Box, point_box_strategy_type >::apply(p[0], box, point_box_strategy_type()); } box_point top_left, top_right, bottom_left, bottom_right; detail::assign_box_corners(box, bottom_left, bottom_right, top_left, top_right); SBStrategy::mirror(p[0], p[1], bottom_left, bottom_right, top_left, top_right); typedef geometry::less<segment_point, -1, typename SBStrategy::cs_tag> less_type; if (less_type()(p[0], p[1])) { return segment_to_box_2D < return_type, segment_point, box_point, SBStrategy >::apply(p[0], p[1], top_left, top_right, bottom_left, bottom_right, sb_strategy); } else { return segment_to_box_2D < return_type, segment_point, box_point, SBStrategy >::apply(p[1], p[0], top_left, top_right, bottom_left, bottom_right, sb_strategy); } } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Segment, typename Box, typename Strategy> struct distance < Segment, Box, Strategy, segment_tag, box_tag, strategy_tag_distance_segment_box, false > { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Segment>::type, typename point_type<Box>::type >::type return_type; static inline return_type apply(Segment const& segment, Box const& box, Strategy const& strategy) { assert_dimension_equal<Segment, Box>(); return detail::distance::segment_to_box < Segment, Box, dimension<Segment>::value, Strategy >::apply(segment, box, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP detail/distance/implementation.hpp 0000644 00000003577 15125631656 0013364 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2018. // Modifications copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP // the implementation details #include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp> #include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp> #include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp> #include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp> #include <boost/geometry/algorithms/detail/distance/linear_to_box.hpp> #include <boost/geometry/algorithms/detail/distance/geometry_to_segment_or_box.hpp> #include <boost/geometry/algorithms/detail/distance/segment_to_segment.hpp> #include <boost/geometry/algorithms/detail/distance/segment_to_box.hpp> #include <boost/geometry/algorithms/detail/distance/box_to_box.hpp> #include <boost/geometry/algorithms/detail/distance/backward_compatibility.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP detail/distance/multipoint_to_geometry.hpp 0000644 00000017202 15125631656 0015146 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2019, 2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template <typename MultiPoint1, typename MultiPoint2, typename Strategy> struct multipoint_to_multipoint { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<MultiPoint1>::type, typename point_type<MultiPoint2>::type >::type return_type; static inline return_type apply(MultiPoint1 const& multipoint1, MultiPoint2 const& multipoint2, Strategy const& strategy) { if (boost::size(multipoint2) < boost::size(multipoint1)) { return point_or_segment_range_to_geometry_rtree < typename boost::range_iterator<MultiPoint2 const>::type, MultiPoint1, Strategy >::apply(boost::begin(multipoint2), boost::end(multipoint2), multipoint1, strategy); } return point_or_segment_range_to_geometry_rtree < typename boost::range_iterator<MultiPoint1 const>::type, MultiPoint2, Strategy >::apply(boost::begin(multipoint1), boost::end(multipoint1), multipoint2, strategy); } }; template <typename MultiPoint, typename Linear, typename Strategy> struct multipoint_to_linear { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<MultiPoint>::type, typename point_type<Linear>::type >::type return_type; static inline return_type apply(MultiPoint const& multipoint, Linear const& linear, Strategy const& strategy) { return detail::distance::point_or_segment_range_to_geometry_rtree < typename boost::range_iterator<MultiPoint const>::type, Linear, Strategy >::apply(boost::begin(multipoint), boost::end(multipoint), linear, strategy); } static inline return_type apply(Linear const& linear, MultiPoint const& multipoint, Strategy const& strategy) { return apply(multipoint, linear, strategy); } }; template <typename MultiPoint, typename Areal, typename Strategy> class multipoint_to_areal { private: template <typename CoveredByStrategy> struct not_covered_by_areal { not_covered_by_areal(Areal const& areal, CoveredByStrategy const& strategy) : m_areal(areal), m_strategy(strategy) {} template <typename Point> inline bool apply(Point const& point) const { return !geometry::covered_by(point, m_areal, m_strategy); } Areal const& m_areal; CoveredByStrategy const& m_strategy; }; public: typedef typename strategy::distance::services::return_type < Strategy, typename point_type<MultiPoint>::type, typename point_type<Areal>::type >::type return_type; static inline return_type apply(MultiPoint const& multipoint, Areal const& areal, Strategy const& strategy) { typedef typename Strategy::point_in_geometry_strategy_type pg_strategy_type; typedef not_covered_by_areal<pg_strategy_type> predicate_type; // predicate holds references so the strategy has to be created here pg_strategy_type pg_strategy = strategy.get_point_in_geometry_strategy(); predicate_type predicate(areal, pg_strategy); if (check_iterator_range < predicate_type, false >::apply(boost::begin(multipoint), boost::end(multipoint), predicate)) { return detail::distance::point_or_segment_range_to_geometry_rtree < typename boost::range_iterator<MultiPoint const>::type, Areal, Strategy >::apply(boost::begin(multipoint), boost::end(multipoint), areal, strategy); } return 0; } static inline return_type apply(Areal const& areal, MultiPoint const& multipoint, Strategy const& strategy) { return apply(multipoint, areal, strategy); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename MultiPoint1, typename MultiPoint2, typename Strategy> struct distance < MultiPoint1, MultiPoint2, Strategy, multi_point_tag, multi_point_tag, strategy_tag_distance_point_point, false > : detail::distance::multipoint_to_multipoint < MultiPoint1, MultiPoint2, Strategy > {}; template <typename MultiPoint, typename Linear, typename Strategy> struct distance < MultiPoint, Linear, Strategy, multi_point_tag, linear_tag, strategy_tag_distance_point_segment, false > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy> {}; template <typename Linear, typename MultiPoint, typename Strategy> struct distance < Linear, MultiPoint, Strategy, linear_tag, multi_point_tag, strategy_tag_distance_point_segment, false > : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy> {}; template <typename MultiPoint, typename Areal, typename Strategy> struct distance < MultiPoint, Areal, Strategy, multi_point_tag, areal_tag, strategy_tag_distance_point_segment, false > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy> {}; template <typename Areal, typename MultiPoint, typename Strategy> struct distance < Areal, MultiPoint, Strategy, areal_tag, multi_point_tag, strategy_tag_distance_point_segment, false > : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP detail/distance/box_to_box.hpp 0000644 00000002747 15125631657 0012500 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP #include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Box1, typename Box2, typename Strategy> struct distance < Box1, Box2, Strategy, box_tag, box_tag, strategy_tag_distance_box_box, false > { static inline typename strategy::distance::services::return_type < Strategy, typename point_type<Box1>::type, typename point_type<Box2>::type >::type apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) { boost::ignore_unused(strategy); return strategy.apply(box1, box2); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP detail/distance/linear_to_box.hpp 0000644 00000006231 15125631657 0013152 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2018, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/algorithms/intersects.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template <typename Linear, typename Box, typename Strategy> struct linear_to_box { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Linear>::type, typename point_type<Box>::type >::type return_type; template <typename Iterator> static inline return_type apply(Box const& box, Iterator begin, Iterator end, Strategy const& strategy) { bool first = true; return_type d_min(0); for (Iterator it = begin; it != end; ++it, first = false) { typedef typename std::iterator_traits<Iterator>::value_type Segment; return_type d = dispatch::distance<Segment, Box, Strategy> ::apply(*it, box, strategy); if ( first || d < d_min ) { d_min = d; } } return d_min; } static inline return_type apply(Linear const& linear, Box const& box, Strategy const& strategy) { if ( geometry::intersects(linear, box) ) { return 0; } return apply(box, geometry::segments_begin(linear), geometry::segments_end(linear), strategy); } static inline return_type apply(Box const& box, Linear const& linear, Strategy const& strategy) { return apply(linear, box, strategy); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear, typename Box, typename Strategy> struct distance < Linear, Box, Strategy, linear_tag, box_tag, strategy_tag_distance_segment_box, false > : detail::distance::linear_to_box < Linear, Box, Strategy > {}; template <typename Areal, typename Box, typename Strategy> struct distance < Areal, Box, Strategy, areal_tag, box_tag, strategy_tag_distance_segment_box, false > : detail::distance::linear_to_box < Areal, Box, Strategy > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP detail/distance/default_strategies.hpp 0000644 00000012630 15125631657 0014204 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/strategies/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { // Helper metafunction for default strategy retrieval template < typename Geometry1, typename Geometry2 = Geometry1, typename Tag1 = typename tag_cast < typename tag<Geometry1>::type, pointlike_tag >::type, typename Tag2 = typename tag_cast < typename tag<Geometry2>::type, pointlike_tag >::type, bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value > struct default_strategy : strategy::distance::services::default_strategy < point_tag, segment_tag, typename point_type<Geometry1>::type, typename point_type<Geometry2>::type > {}; template < typename Geometry1, typename Geometry2, typename Tag1, typename Tag2 > struct default_strategy<Geometry1, Geometry2, Tag1, Tag2, true> : default_strategy<Geometry2, Geometry1, Tag2, Tag1, false> {}; template <typename Pointlike1, typename Pointlike2> struct default_strategy < Pointlike1, Pointlike2, pointlike_tag, pointlike_tag, false > : strategy::distance::services::default_strategy < point_tag, point_tag, typename point_type<Pointlike1>::type, typename point_type<Pointlike2>::type > {}; template <typename Pointlike, typename Box> struct default_strategy<Pointlike, Box, pointlike_tag, box_tag, false> : strategy::distance::services::default_strategy < point_tag, box_tag, typename point_type<Pointlike>::type, typename point_type<Box>::type > {}; template <typename Box1, typename Box2> struct default_strategy<Box1, Box2, box_tag, box_tag, false> : strategy::distance::services::default_strategy < box_tag, box_tag, typename point_type<Box1>::type, typename point_type<Box2>::type > {}; template <typename PolygonalOrLinear, typename Box> struct default_strategy_polygonal_or_linear : strategy::distance::services::default_strategy < segment_tag, box_tag, typename point_type<PolygonalOrLinear>::type, typename point_type<Box>::type > {}; template <typename Linear, typename Box> struct default_strategy<Linear, Box, segment_tag, box_tag, false> : default_strategy_polygonal_or_linear<Linear, Box> {}; template <typename Linear, typename Box> struct default_strategy<Linear, Box, linestring_tag, box_tag, false> : default_strategy_polygonal_or_linear<Linear, Box> {}; template <typename Linear, typename Box> struct default_strategy<Linear, Box, multi_linestring_tag, box_tag, false> : default_strategy_polygonal_or_linear<Linear, Box> {}; template <typename Polygonal, typename Box> struct default_strategy<Polygonal, Box, polygon_tag, box_tag, false> : default_strategy_polygonal_or_linear<Polygonal, Box> {}; template <typename Polygonal, typename Box> struct default_strategy<Polygonal, Box, ring_tag, box_tag, false> : default_strategy_polygonal_or_linear<Polygonal, Box> {}; template <typename Polygonal, typename Box> struct default_strategy<Polygonal, Box, multi_polygon_tag, box_tag, false> : default_strategy_polygonal_or_linear<Polygonal, Box> {}; // Helper metafunction for default point-segment strategy retrieval template <typename Geometry1, typename Geometry2, typename Strategy> struct default_ps_strategy : strategy::distance::services::default_strategy < point_tag, segment_tag, typename point_type<Geometry1>::type, typename point_type<Geometry2>::type, typename cs_tag<typename point_type<Geometry1>::type>::type, typename cs_tag<typename point_type<Geometry2>::type>::type, Strategy > {}; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_DEFAULT_STRATEGIES_HPP detail/distance/interface.hpp 0000644 00000027576 15125631657 0012305 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP #include <boost/concept_check.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/default_distance_result.hpp> #include <boost/geometry/strategies/distance_result.hpp> #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // If reversal is needed, perform it template < typename Geometry1, typename Geometry2, typename Strategy, typename Tag1, typename Tag2, typename StrategyTag > struct distance < Geometry1, Geometry2, Strategy, Tag1, Tag2, StrategyTag, true > : distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false> { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Geometry2>::type, typename point_type<Geometry1>::type >::type return_type; static inline return_type apply( Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { return distance < Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false >::apply(g2, g1, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { template <typename Strategy> struct distance { template <typename Geometry1, typename Geometry2> static inline typename distance_result<Geometry1, Geometry2, Strategy>::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return dispatch::distance < Geometry1, Geometry2, Strategy >::apply(geometry1, geometry2, strategy); } }; template <> struct distance<default_strategy> { template <typename Geometry1, typename Geometry2> static inline typename distance_result<Geometry1, Geometry2, default_strategy>::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename detail::distance::default_strategy < Geometry1, Geometry2 >::type strategy_type; return dispatch::distance < Geometry1, Geometry2, strategy_type >::apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct distance { template <typename Strategy> static inline typename distance_result<Geometry1, Geometry2, Strategy>::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_strategy::distance < Strategy >::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: static_visitor < typename distance_result < variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2, Strategy >::type > { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2), m_strategy(strategy) {} template <typename Geometry1> typename distance_result<Geometry1, Geometry2, Strategy>::type operator()(Geometry1 const& geometry1) const { return distance < Geometry1, Geometry2 >::template apply < Strategy >(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline typename distance_result < variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2, Strategy >::type apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: static_visitor < typename distance_result < Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy >::type > { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1), m_strategy(strategy) {} template <typename Geometry2> typename distance_result<Geometry1, Geometry2, Strategy>::type operator()(Geometry2 const& geometry2) const { return distance < Geometry1, Geometry2 >::template apply < Strategy >(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline typename distance_result < Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy >::type apply( Geometry1 const& geometry1, const variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct distance < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: static_visitor < typename distance_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type > { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> typename distance_result<Geometry1, Geometry2, Strategy>::type operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return distance < Geometry1, Geometry2 >::template apply < Strategy >(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline typename distance_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief Calculate the distance between two geometries \brief_strategy \ingroup distance \details \details The free function distance calculates the distance between two geometries \brief_strategy. \details_strategy_reasons \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Distance} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{distance} \return \return_calc{distance} \note The strategy can be a point-point strategy. In case of distance point-line/point-polygon it may also be a point-segment strategy. \qbk{distinguish,with strategy} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)] \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)] \* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)] \* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)] \* more (currently extensions): Vincenty\, Andoyer (geographic) } */ /* Note, in case of a Compilation Error: if you get: - "Failed to specialize function template ..." - "error: no matching function for call to ..." for distance, it is probably so that there is no specialization for return_type<...> for your strategy. */ template <typename Geometry1, typename Geometry2, typename Strategy> inline typename distance_result<Geometry1, Geometry2, Strategy>::type distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); detail::throw_on_empty_input(geometry1); detail::throw_on_empty_input(geometry2); return resolve_variant::distance < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief Calculate the distance between two geometries. \ingroup distance \details The free function distance calculates the distance between two geometries. \details_default_strategy \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_calc{distance} \qbk{[include reference/algorithms/distance.qbk]} */ template <typename Geometry1, typename Geometry2> inline typename default_distance_result<Geometry1, Geometry2>::type distance(Geometry1 const& geometry1, Geometry2 const& geometry2) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return geometry::distance(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP detail/distance/iterator_selector.hpp 0000644 00000003312 15125631657 0014054 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP #define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/iterators/point_iterator.hpp> #include <boost/geometry/iterators/segment_iterator.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { // class to choose between point_iterator and segment_iterator template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct iterator_selector { typedef geometry::segment_iterator<Geometry> iterator_type; static inline iterator_type begin(Geometry& geometry) { return segments_begin(geometry); } static inline iterator_type end(Geometry& geometry) { return segments_end(geometry); } }; template <typename MultiPoint> struct iterator_selector<MultiPoint, multi_point_tag> { typedef geometry::point_iterator<MultiPoint> iterator_type; static inline iterator_type begin(MultiPoint& multipoint) { return points_begin(multipoint); } static inline iterator_type end(MultiPoint& multipoint) { return points_end(multipoint); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP detail/distance/backward_compatibility.hpp 0000644 00000022722 15125631657 0015040 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> #include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp> #include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template<typename Point, typename Segment, typename Strategy> struct point_to_segment { static inline typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Segment>::type >::type apply(Point const& point, Segment const& segment, Strategy const& ) { typename detail::distance::default_ps_strategy < Point, typename point_type<Segment>::type, Strategy >::type segment_strategy; typename point_type<Segment>::type p[2]; geometry::detail::assign_point_from_index<0>(segment, p[0]); geometry::detail::assign_point_from_index<1>(segment, p[1]); return segment_strategy.apply(point, p[0], p[1]); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Point-segment version 1, with point-point strategy template <typename Point, typename Segment, typename Strategy> struct distance < Point, Segment, Strategy, point_tag, segment_tag, strategy_tag_distance_point_point, false > : detail::distance::point_to_segment<Point, Segment, Strategy> {}; // Point-line version 1, where point-point strategy is specified template <typename Point, typename Linestring, typename Strategy> struct distance < Point, Linestring, Strategy, point_tag, linestring_tag, strategy_tag_distance_point_point, false > { static inline typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Linestring>::type >::type apply(Point const& point, Linestring const& linestring, Strategy const&) { typedef typename detail::distance::default_ps_strategy < Point, typename point_type<Linestring>::type, Strategy >::type ps_strategy_type; return detail::distance::point_to_range < Point, Linestring, closed, ps_strategy_type >::apply(point, linestring, ps_strategy_type()); } }; // Point-ring , where point-point strategy is specified template <typename Point, typename Ring, typename Strategy> struct distance < Point, Ring, Strategy, point_tag, ring_tag, strategy_tag_distance_point_point, false > { typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Ring>::type >::type return_type; static inline return_type apply(Point const& point, Ring const& ring, Strategy const&) { typedef typename detail::distance::default_ps_strategy < Point, typename point_type<Ring>::type, Strategy >::type ps_strategy_type; return detail::distance::point_to_ring < Point, Ring, geometry::closure<Ring>::value, ps_strategy_type >::apply(point, ring, ps_strategy_type()); } }; // Point-polygon , where point-point strategy is specified template <typename Point, typename Polygon, typename Strategy> struct distance < Point, Polygon, Strategy, point_tag, polygon_tag, strategy_tag_distance_point_point, false > { typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<Polygon>::type >::type return_type; static inline return_type apply(Point const& point, Polygon const& polygon, Strategy const&) { typedef typename detail::distance::default_ps_strategy < Point, typename point_type<Polygon>::type, Strategy >::type ps_strategy_type; return detail::distance::point_to_polygon < Point, Polygon, geometry::closure<Polygon>::value, ps_strategy_type >::apply(point, polygon, ps_strategy_type()); } }; template < typename Point, typename MultiGeometry, typename MultiGeometryTag, typename Strategy > struct distance < Point, MultiGeometry, Strategy, point_tag, MultiGeometryTag, strategy_tag_distance_point_point, false > { typedef typename strategy::distance::services::return_type < Strategy, Point, typename point_type<MultiGeometry>::type >::type return_type; static inline return_type apply(Point const& point, MultiGeometry const& multigeometry, Strategy const&) { typedef typename detail::distance::default_ps_strategy < Point, typename point_type<MultiGeometry>::type, Strategy >::type ps_strategy_type; return distance < Point, MultiGeometry, ps_strategy_type, point_tag, MultiGeometryTag, strategy_tag_distance_point_segment, false >::apply(point, multigeometry, ps_strategy_type()); } }; template < typename Geometry, typename MultiPoint, typename GeometryTag, typename Strategy > struct distance < Geometry, MultiPoint, Strategy, GeometryTag, multi_point_tag, strategy_tag_distance_point_point, false > { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<MultiPoint>::type, typename point_type<Geometry>::type >::type return_type; static inline return_type apply(Geometry const& geometry, MultiPoint const& multipoint, Strategy const&) { typedef typename detail::distance::default_ps_strategy < typename point_type<MultiPoint>::type, typename point_type<Geometry>::type, Strategy >::type ps_strategy_type; return distance < Geometry, MultiPoint, ps_strategy_type, GeometryTag, multi_point_tag, strategy_tag_distance_point_segment, false >::apply(geometry, multipoint, ps_strategy_type()); } }; template < typename MultiPoint, typename MultiGeometry, typename MultiGeometryTag, typename Strategy > struct distance < MultiPoint, MultiGeometry, Strategy, multi_point_tag, MultiGeometryTag, strategy_tag_distance_point_point, false > { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<MultiPoint>::type, typename point_type<MultiGeometry>::type >::type return_type; static inline return_type apply(MultiPoint const& multipoint, MultiGeometry const& multigeometry, Strategy const&) { typedef typename detail::distance::default_ps_strategy < typename point_type<MultiPoint>::type, typename point_type<MultiGeometry>::type, Strategy >::type ps_strategy_type; return distance < MultiPoint, MultiGeometry, ps_strategy_type, multi_point_tag, MultiGeometryTag, strategy_tag_distance_point_segment, false >::apply(multipoint, multigeometry, ps_strategy_type()); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BACKWARD_COMPATIBILITY_HPP detail/distance/linear_to_linear.hpp 0000644 00000007021 15125631657 0013632 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/iterators/point_iterator.hpp> #include <boost/geometry/iterators/segment_iterator.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/algorithms/num_segments.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template <typename Linear1, typename Linear2, typename Strategy> struct linear_to_linear { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Linear1>::type, typename point_type<Linear2>::type >::type return_type; static inline return_type apply(Linear1 const& linear1, Linear2 const& linear2, Strategy const& strategy, bool = false) { if (geometry::num_points(linear1) == 1) { return dispatch::distance < typename point_type<Linear1>::type, Linear2, Strategy >::apply(*points_begin(linear1), linear2, strategy); } if (geometry::num_points(linear2) == 1) { return dispatch::distance < typename point_type<Linear2>::type, Linear1, Strategy >::apply(*points_begin(linear2), linear1, strategy); } if (geometry::num_segments(linear2) < geometry::num_segments(linear1)) { return point_or_segment_range_to_geometry_rtree < geometry::segment_iterator<Linear2 const>, Linear1, Strategy >::apply(geometry::segments_begin(linear2), geometry::segments_end(linear2), linear1, strategy); } return point_or_segment_range_to_geometry_rtree < geometry::segment_iterator<Linear1 const>, Linear2, Strategy >::apply(geometry::segments_begin(linear1), geometry::segments_end(linear1), linear2, strategy); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear1, typename Linear2, typename Strategy> struct distance < Linear1, Linear2, Strategy, linear_tag, linear_tag, strategy_tag_distance_point_segment, false > : detail::distance::linear_to_linear < Linear1, Linear2, Strategy > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP detail/distance/linear_or_areal_to_areal.hpp 0000644 00000007532 15125631657 0015317 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { template <typename Linear, typename Areal, typename Strategy> struct linear_to_areal { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Linear>::type, typename point_type<Areal>::type >::type return_type; static inline return_type apply(Linear const& linear, Areal const& areal, Strategy const& strategy) { if ( geometry::intersects(linear, areal, strategy.get_relate_segment_segment_strategy()) ) { return 0; } return linear_to_linear < Linear, Areal, Strategy >::apply(linear, areal, strategy, false); } static inline return_type apply(Areal const& areal, Linear const& linear, Strategy const& strategy) { return apply(linear, areal, strategy); } }; template <typename Areal1, typename Areal2, typename Strategy> struct areal_to_areal { typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Areal1>::type, typename point_type<Areal2>::type >::type return_type; static inline return_type apply(Areal1 const& areal1, Areal2 const& areal2, Strategy const& strategy) { if ( geometry::intersects(areal1, areal2, strategy.get_relate_segment_segment_strategy()) ) { return 0; } return linear_to_linear < Areal1, Areal2, Strategy >::apply(areal1, areal2, strategy, false); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear, typename Areal, typename Strategy> struct distance < Linear, Areal, Strategy, linear_tag, areal_tag, strategy_tag_distance_point_segment, false > : detail::distance::linear_to_areal < Linear, Areal, Strategy > {}; template <typename Areal, typename Linear, typename Strategy> struct distance < Areal, Linear, Strategy, areal_tag, linear_tag, strategy_tag_distance_point_segment, false > : detail::distance::linear_to_areal < Linear, Areal, Strategy > {}; template <typename Areal1, typename Areal2, typename Strategy> struct distance < Areal1, Areal2, Strategy, areal_tag, areal_tag, strategy_tag_distance_point_segment, false > : detail::distance::areal_to_areal < Areal1, Areal2, Strategy > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP detail/distance/geometry_to_segment_or_box.hpp 0000644 00000034140 15125631657 0015755 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP #include <iterator> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/iterators/point_iterator.hpp> #include <boost/geometry/iterators/segment_iterator.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/algorithms/detail/closest_feature/geometry_to_range.hpp> #include <boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp> #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { // closure of segment or box point range template < typename SegmentOrBox, typename Tag = typename tag<SegmentOrBox>::type > struct segment_or_box_point_range_closure : not_implemented<SegmentOrBox> {}; template <typename Segment> struct segment_or_box_point_range_closure<Segment, segment_tag> { static const closure_selector value = closed; }; template <typename Box> struct segment_or_box_point_range_closure<Box, box_tag> { static const closure_selector value = open; }; template < typename Geometry, typename SegmentOrBox, typename Strategy, typename Tag = typename tag<Geometry>::type > class geometry_to_segment_or_box { private: typedef typename point_type<SegmentOrBox>::type segment_or_box_point; typedef typename strategy::distance::services::comparable_type < Strategy >::type comparable_strategy; typedef detail::closest_feature::point_to_point_range < typename point_type<Geometry>::type, std::vector<segment_or_box_point>, segment_or_box_point_range_closure<SegmentOrBox>::value, comparable_strategy > point_to_point_range; typedef detail::closest_feature::geometry_to_range geometry_to_range; typedef typename strategy::distance::services::return_type < comparable_strategy, typename point_type<Geometry>::type, segment_or_box_point >::type comparable_return_type; // assign the new minimum value for an iterator of the point range // of a segment or a box template < typename SegOrBox, typename SegOrBoxTag = typename tag<SegOrBox>::type > struct assign_new_min_iterator : not_implemented<SegOrBox> {}; template <typename Segment> struct assign_new_min_iterator<Segment, segment_tag> { template <typename Iterator> static inline void apply(Iterator&, Iterator) { } }; template <typename Box> struct assign_new_min_iterator<Box, box_tag> { template <typename Iterator> static inline void apply(Iterator& it_min, Iterator it) { it_min = it; } }; // assign the points of a segment or a box to a range template < typename SegOrBox, typename PointRange, typename SegOrBoxTag = typename tag<SegOrBox>::type > struct assign_segment_or_box_points {}; template <typename Segment, typename PointRange> struct assign_segment_or_box_points<Segment, PointRange, segment_tag> { static inline void apply(Segment const& segment, PointRange& range) { detail::assign_point_from_index<0>(segment, range[0]); detail::assign_point_from_index<1>(segment, range[1]); } }; template <typename Box, typename PointRange> struct assign_segment_or_box_points<Box, PointRange, box_tag> { static inline void apply(Box const& box, PointRange& range) { detail::assign_box_corners_oriented<true>(box, range); } }; template < typename SegOrBox, typename SegOrBoxTag = typename tag<SegOrBox>::type > struct intersects { static inline bool apply(Geometry const& g1, SegOrBox const& g2, Strategy const&) { return geometry::intersects(g1, g2); } }; template <typename SegOrBox> struct intersects<SegOrBox, segment_tag> { static inline bool apply(Geometry const& g1, SegOrBox const& g2, Strategy const& s) { return geometry::intersects(g1, g2, s.get_relate_segment_segment_strategy()); } }; public: typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Geometry>::type, segment_or_box_point >::type return_type; static inline return_type apply(Geometry const& geometry, SegmentOrBox const& segment_or_box, Strategy const& strategy, bool check_intersection = true) { typedef geometry::point_iterator<Geometry const> point_iterator_type; typedef geometry::segment_iterator < Geometry const > segment_iterator_type; typedef typename boost::range_const_iterator < std::vector<segment_or_box_point> >::type seg_or_box_const_iterator; typedef assign_new_min_iterator<SegmentOrBox> assign_new_value; if (check_intersection && intersects<SegmentOrBox>::apply(geometry, segment_or_box, strategy)) { return 0; } comparable_strategy cstrategy = strategy::distance::services::get_comparable < Strategy >::apply(strategy); // get all points of the segment or the box std::vector<segment_or_box_point> seg_or_box_points(geometry::num_points(segment_or_box)); assign_segment_or_box_points < SegmentOrBox, std::vector<segment_or_box_point> >::apply(segment_or_box, seg_or_box_points); // consider all distances of the points in the geometry to the // segment or box comparable_return_type cd_min1(0); point_iterator_type pit_min; seg_or_box_const_iterator it_min1 = boost::const_begin(seg_or_box_points); seg_or_box_const_iterator it_min2 = it_min1; ++it_min2; bool first = true; for (point_iterator_type pit = points_begin(geometry); pit != points_end(geometry); ++pit, first = false) { comparable_return_type cd; std::pair < seg_or_box_const_iterator, seg_or_box_const_iterator > it_pair = point_to_point_range::apply(*pit, boost::const_begin(seg_or_box_points), boost::const_end(seg_or_box_points), cstrategy, cd); if (first || cd < cd_min1) { cd_min1 = cd; pit_min = pit; assign_new_value::apply(it_min1, it_pair.first); assign_new_value::apply(it_min2, it_pair.second); } } // consider all distances of the points in the segment or box to the // segments of the geometry comparable_return_type cd_min2(0); segment_iterator_type sit_min; seg_or_box_const_iterator it_min; first = true; for (seg_or_box_const_iterator it = boost::const_begin(seg_or_box_points); it != boost::const_end(seg_or_box_points); ++it, first = false) { comparable_return_type cd; segment_iterator_type sit = geometry_to_range::apply(*it, segments_begin(geometry), segments_end(geometry), cstrategy, cd); if (first || cd < cd_min2) { cd_min2 = cd; it_min = it; sit_min = sit; } } if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) { return (std::min)(cd_min1, cd_min2); } if (cd_min1 < cd_min2) { return strategy.apply(*pit_min, *it_min1, *it_min2); } else { return dispatch::distance < segment_or_box_point, typename std::iterator_traits < segment_iterator_type >::value_type, Strategy >::apply(*it_min, *sit_min, strategy); } } static inline return_type apply(SegmentOrBox const& segment_or_box, Geometry const& geometry, Strategy const& strategy, bool check_intersection = true) { return apply(geometry, segment_or_box, strategy, check_intersection); } }; template <typename MultiPoint, typename SegmentOrBox, typename Strategy> class geometry_to_segment_or_box < MultiPoint, SegmentOrBox, Strategy, multi_point_tag > { private: typedef detail::closest_feature::geometry_to_range base_type; typedef typename boost::range_iterator < MultiPoint const >::type iterator_type; typedef detail::closest_feature::geometry_to_range geometry_to_range; public: typedef typename strategy::distance::services::return_type < Strategy, typename point_type<SegmentOrBox>::type, typename point_type<MultiPoint>::type >::type return_type; static inline return_type apply(MultiPoint const& multipoint, SegmentOrBox const& segment_or_box, Strategy const& strategy) { namespace sds = strategy::distance::services; typename sds::return_type < typename sds::comparable_type<Strategy>::type, typename point_type<SegmentOrBox>::type, typename point_type<MultiPoint>::type >::type cd_min; iterator_type it_min = geometry_to_range::apply(segment_or_box, boost::begin(multipoint), boost::end(multipoint), sds::get_comparable < Strategy >::apply(strategy), cd_min); return is_comparable<Strategy>::value ? cd_min : dispatch::distance < typename point_type<MultiPoint>::type, SegmentOrBox, Strategy >::apply(*it_min, segment_or_box, strategy); } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear, typename Segment, typename Strategy> struct distance < Linear, Segment, Strategy, linear_tag, segment_tag, strategy_tag_distance_point_segment, false > : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy> {}; template <typename Areal, typename Segment, typename Strategy> struct distance < Areal, Segment, Strategy, areal_tag, segment_tag, strategy_tag_distance_point_segment, false > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> {}; template <typename Segment, typename Areal, typename Strategy> struct distance < Segment, Areal, Strategy, segment_tag, areal_tag, strategy_tag_distance_point_segment, false > : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy> {}; template <typename Linear, typename Box, typename Strategy> struct distance < Linear, Box, Strategy, linear_tag, box_tag, strategy_tag_distance_point_segment, false > : detail::distance::geometry_to_segment_or_box < Linear, Box, Strategy > {}; template <typename Areal, typename Box, typename Strategy> struct distance < Areal, Box, Strategy, areal_tag, box_tag, strategy_tag_distance_point_segment, false > : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy> {}; template <typename MultiPoint, typename Segment, typename Strategy> struct distance < MultiPoint, Segment, Strategy, multi_point_tag, segment_tag, strategy_tag_distance_point_segment, false > : detail::distance::geometry_to_segment_or_box < MultiPoint, Segment, Strategy > {}; template <typename MultiPoint, typename Box, typename Strategy> struct distance < MultiPoint, Box, Strategy, multi_point_tag, box_tag, strategy_tag_distance_point_box, false > : detail::distance::geometry_to_segment_or_box < MultiPoint, Box, Strategy > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP detail/distance/segment_to_segment.hpp 0000644 00000010037 15125631657 0014213 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP #include <algorithm> #include <iterator> #include <boost/core/addressof.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/tags.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/detail/distance/is_comparable.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace distance { // compute segment-segment distance template<typename Segment1, typename Segment2, typename Strategy> class segment_to_segment { private: typedef typename strategy::distance::services::comparable_type < Strategy >::type comparable_strategy; typedef typename strategy::distance::services::return_type < comparable_strategy, typename point_type<Segment1>::type, typename point_type<Segment2>::type >::type comparable_return_type; public: typedef typename strategy::distance::services::return_type < Strategy, typename point_type<Segment1>::type, typename point_type<Segment2>::type >::type return_type; static inline return_type apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& strategy) { if (geometry::intersects(segment1, segment2, strategy.get_relate_segment_segment_strategy())) { return 0; } typename point_type<Segment1>::type p[2]; detail::assign_point_from_index<0>(segment1, p[0]); detail::assign_point_from_index<1>(segment1, p[1]); typename point_type<Segment2>::type q[2]; detail::assign_point_from_index<0>(segment2, q[0]); detail::assign_point_from_index<1>(segment2, q[1]); comparable_strategy cstrategy = strategy::distance::services::get_comparable < Strategy >::apply(strategy); comparable_return_type d[4]; d[0] = cstrategy.apply(q[0], p[0], p[1]); d[1] = cstrategy.apply(q[1], p[0], p[1]); d[2] = cstrategy.apply(p[0], q[0], q[1]); d[3] = cstrategy.apply(p[1], q[0], q[1]); std::size_t imin = std::distance(boost::addressof(d[0]), std::min_element(d, d + 4)); if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value)) { return d[imin]; } switch (imin) { case 0: return strategy.apply(q[0], p[0], p[1]); case 1: return strategy.apply(q[1], p[0], p[1]); case 2: return strategy.apply(p[0], q[0], q[1]); default: return strategy.apply(p[1], q[0], q[1]); } } }; }} // namespace detail::distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // segment-segment template <typename Segment1, typename Segment2, typename Strategy> struct distance < Segment1, Segment2, Strategy, segment_tag, segment_tag, strategy_tag_distance_point_segment, false > : detail::distance::segment_to_segment<Segment1, Segment2, Strategy> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP detail/turns/print_turns.hpp 0000644 00000006353 15125631657 0012303 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_TURNS_PRINT_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP #include <algorithm> #include <iostream> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> #include <boost/geometry/io/wkt/write.hpp> #include <boost/geometry/io/dsv/write.hpp> namespace boost { namespace geometry { namespace detail { namespace turns { struct turn_printer { turn_printer(std::ostream & os) : index(0) , out(os) {} template <typename Turn> void operator()(Turn const& turn) { out << index << ": " << geometry::method_char(turn.method); if ( turn.discarded ) out << " (discarded)\n"; else if ( turn.blocked() ) out << " (blocked)\n"; else out << '\n'; double fraction[2]; fraction[0] = turn.operations[0].fraction.numerator() / turn.operations[0].fraction.denominator(); out << geometry::operation_char(turn.operations[0].operation) <<": seg: " << turn.operations[0].seg_id.source_index << ", m: " << turn.operations[0].seg_id.multi_index << ", r: " << turn.operations[0].seg_id.ring_index << ", s: " << turn.operations[0].seg_id.segment_index; out << ", fr: " << fraction[0]; out << ", col?: " << turn.operations[0].is_collinear; out << ' ' << geometry::dsv(turn.point) << ' '; out << '\n'; fraction[1] = turn.operations[1].fraction.numerator() / turn.operations[1].fraction.denominator(); out << geometry::operation_char(turn.operations[1].operation) << ": seg: " << turn.operations[1].seg_id.source_index << ", m: " << turn.operations[1].seg_id.multi_index << ", r: " << turn.operations[1].seg_id.ring_index << ", s: " << turn.operations[1].seg_id.segment_index; out << ", fr: " << fraction[1]; out << ", col?: " << turn.operations[1].is_collinear; out << ' ' << geometry::dsv(turn.point) << ' '; ++index; out << std::endl; } int index; std::ostream & out; }; template <typename Geometry1, typename Geometry2, typename Turns> static inline void print_turns(Geometry1 const& g1, Geometry2 const& g2, Turns const& turns) { std::cout << geometry::wkt(g1) << std::endl; std::cout << geometry::wkt(g2) << std::endl; std::for_each(boost::begin(turns), boost::end(turns), turn_printer(std::cout)); } }} // namespace detail::turns }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_PRINT_TURNS_HPP detail/turns/remove_duplicate_turns.hpp 0000644 00000002743 15125631657 0014475 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP #include <algorithm> #include <boost/geometry/algorithms/equals.hpp> namespace boost { namespace geometry { namespace detail { namespace turns { template <typename Turns, bool Enable> struct remove_duplicate_turns { static inline void apply(Turns&) {} }; template <typename Turns> class remove_duplicate_turns<Turns, true> { private: struct TurnEqualsTo { template <typename Turn> bool operator()(Turn const& t1, Turn const& t2) const { return geometry::equals(t1.point, t2.point) && t1.operations[0].seg_id == t2.operations[0].seg_id && t1.operations[1].seg_id == t2.operations[1].seg_id; } }; public: static inline void apply(Turns& turns) { turns.erase( std::unique(turns.begin(), turns.end(), TurnEqualsTo()), turns.end() ); } }; }} // namespace detail::turns }} // namespect boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_REMOVE_DUPLICATE_TURNS_HPP detail/turns/filter_continue_turns.hpp 0000644 00000003646 15125631657 0014342 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP #include <algorithm> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> namespace boost { namespace geometry { namespace detail { namespace turns { template <typename Turns, bool Enable> struct filter_continue_turns { static inline void apply(Turns&) {} }; template <typename Turns> class filter_continue_turns<Turns, true> { private: class IsContinueTurn { private: template <typename Operation> inline bool is_continue_or_opposite(Operation const& operation) const { return operation == detail::overlay::operation_continue || operation == detail::overlay::operation_opposite; } public: template <typename Turn> bool operator()(Turn const& turn) const { if ( turn.method != detail::overlay::method_collinear && turn.method != detail::overlay::method_equal ) { return false; } return is_continue_or_opposite(turn.operations[0].operation) && is_continue_or_opposite(turn.operations[1].operation); } }; public: static inline void apply(Turns& turns) { turns.erase( std::remove_if(turns.begin(), turns.end(), IsContinueTurn()), turns.end() ); } }; }} // namespace detail::turns }} // namespect boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_FILTER_CONTINUE_TURNS_HPP detail/turns/debug_turn.hpp 0000644 00000003275 15125631657 0012052 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP #ifdef BOOST_GEOMETRY_DEBUG_TURNS #include <iostream> #include <string> #include <boost/algorithm/string/predicate.hpp> #include <boost/geometry/io/wkt/write.hpp> #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> #endif // BOOST_GEOMETRY_DEBUG_TURNS namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace turns { #ifdef BOOST_GEOMETRY_DEBUG_TURNS template <typename Turn, typename Operation> inline void debug_turn(Turn const& turn, Operation op, std::string const& header) { std::cout << header << " at " << op.seg_id << " meth: " << method_char(turn.method) << " op: " << operation_char(op.operation) << " of: " << operation_char(turn.operations[0].operation) << operation_char(turn.operations[1].operation) << " " << geometry::wkt(turn.point) << std::endl; if (boost::contains(header, "Finished")) { std::cout << std::endl; } } #else template <typename Turn, typename Operation> inline void debug_turn(Turn const& , Operation, const char*) { } #endif // BOOST_GEOMETRY_DEBUG_TURNS }} // namespace detail::turns #endif // DOXYGEN_NO_DETAIL }} // namespace boost:geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_DEBUG_TURN_HPP detail/turns/compare_turns.hpp 0000644 00000007004 15125631657 0012567 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2015, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP #include <cstddef> #include <functional> #include <boost/geometry/util/math.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> namespace boost { namespace geometry { namespace detail { namespace turns { // TURNS SORTING AND SEARCHING // sort turns by G1 - source_index == 0 by: // seg_id -> fraction -> other_id -> operation template < typename IdLess = std::less<signed_size_type>, int N = 0, int U = 1, int I = 2, int B = 3, int C = 4, int O = 0, std::size_t OpId = 0 > struct less_seg_fraction_other_op { BOOST_STATIC_ASSERT(OpId < 2); static const std::size_t other_op_id = (OpId + 1) % 2; template <typename Op> static inline int order_op(Op const& op) { switch (op.operation) { case detail::overlay::operation_none : return N; case detail::overlay::operation_union : return U; case detail::overlay::operation_intersection : return I; case detail::overlay::operation_blocked : return B; case detail::overlay::operation_continue : return C; case detail::overlay::operation_opposite : return O; } return -1; } template <typename Op> static inline bool use_operation(Op const& left, Op const& right) { return order_op(left) < order_op(right); } template <typename Turn> static inline bool use_other_id(Turn const& left, Turn const& right) { segment_identifier const& left_other_seg_id = left.operations[other_op_id].seg_id; segment_identifier const& right_other_seg_id = right.operations[other_op_id].seg_id; if ( left_other_seg_id.multi_index != right_other_seg_id.multi_index ) { return left_other_seg_id.multi_index < right_other_seg_id.multi_index; } if ( left_other_seg_id.ring_index != right_other_seg_id.ring_index ) { return left_other_seg_id.ring_index != right_other_seg_id.ring_index; } if ( left_other_seg_id.segment_index != right_other_seg_id.segment_index ) { return IdLess()(left_other_seg_id.segment_index, right_other_seg_id.segment_index); } return use_operation(left.operations[OpId], right.operations[OpId]); } template <typename Turn> static inline bool use_fraction(Turn const& left, Turn const& right) { return geometry::math::equals(left.operations[OpId].fraction, right.operations[OpId].fraction) ? use_other_id(left, right) : (left.operations[OpId].fraction < right.operations[OpId].fraction) ; } template <typename Turn> inline bool operator()(Turn const& left, Turn const& right) const { segment_identifier const& sl = left.operations[OpId].seg_id; segment_identifier const& sr = right.operations[OpId].seg_id; return sl < sr || ( sl == sr && use_fraction(left, right) ); } }; }} // namespace detail::turns }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TURNS_COMPARE_TURNS_HPP detail/assign_values.hpp 0000644 00000021601 15125631657 0011375 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018-2020. // Modifications copyright (c) 2018-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP #define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP #include <cstddef> #include <type_traits> #include <boost/concept/requires.hpp> #include <boost/concept_check.hpp> #include <boost/numeric/conversion/bounds.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp> #include <boost/geometry/util/for_each_coordinate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace assign { template <std::size_t Index, std::size_t Dimension, std::size_t DimensionCount> struct initialize { template <typename Box> static inline void apply(Box& box, typename coordinate_type<Box>::type const& value) { geometry::set<Index, Dimension>(box, value); initialize<Index, Dimension + 1, DimensionCount>::apply(box, value); } }; template <std::size_t Index, std::size_t DimensionCount> struct initialize<Index, DimensionCount, DimensionCount> { template <typename Box> static inline void apply(Box&, typename coordinate_type<Box>::type const&) {} }; struct assign_zero_point { template <typename Point> static inline void apply(Point& point) { geometry::assign_value(point, 0); } }; struct assign_inverse_box_or_segment { template <typename BoxOrSegment> static inline void apply(BoxOrSegment& geometry) { typedef typename point_type<BoxOrSegment>::type point_type; typedef typename coordinate_type<point_type>::type bound_type; initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply( geometry, geometry::bounds<bound_type>::highest() ); initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply( geometry, geometry::bounds<bound_type>::lowest() ); } }; struct assign_zero_box_or_segment { template <typename BoxOrSegment> static inline void apply(BoxOrSegment& geometry) { typedef typename coordinate_type<BoxOrSegment>::type coordinate_type; initialize<0, 0, dimension<BoxOrSegment>::type::value>::apply( geometry, coordinate_type() ); initialize<1, 0, dimension<BoxOrSegment>::type::value>::apply( geometry, coordinate_type() ); } }; template < std::size_t Corner1, std::size_t Corner2, typename Box, typename Point > inline void assign_box_2d_corner(Box const& box, Point& point) { // Be sure both are 2-Dimensional assert_dimension<Box, 2>(); assert_dimension<Point, 2>(); // Copy coordinates typedef typename coordinate_type<Point>::type coordinate_type; geometry::set<0>(point, boost::numeric_cast<coordinate_type>(get<Corner1, 0>(box))); geometry::set<1>(point, boost::numeric_cast<coordinate_type>(get<Corner2, 1>(box))); } template < typename Geometry, typename Point, std::size_t Index, std::size_t Dimension, std::size_t DimensionCount > struct assign_point_to_index { static inline void apply(Point const& point, Geometry& geometry) { geometry::set<Index, Dimension>(geometry, boost::numeric_cast < typename coordinate_type<Geometry>::type >(geometry::get<Dimension>(point))); assign_point_to_index < Geometry, Point, Index, Dimension + 1, DimensionCount >::apply(point, geometry); } }; template < typename Geometry, typename Point, std::size_t Index, std::size_t DimensionCount > struct assign_point_to_index < Geometry, Point, Index, DimensionCount, DimensionCount > { static inline void apply(Point const& , Geometry& ) { } }; template < typename Geometry, typename Point, std::size_t Index, std::size_t Dimension, std::size_t DimensionCount > struct assign_point_from_index { static inline void apply(Geometry const& geometry, Point& point) { geometry::set<Dimension>( point, boost::numeric_cast < typename coordinate_type<Point>::type >(geometry::get<Index, Dimension>(geometry))); assign_point_from_index < Geometry, Point, Index, Dimension + 1, DimensionCount >::apply(geometry, point); } }; template < typename Geometry, typename Point, std::size_t Index, std::size_t DimensionCount > struct assign_point_from_index < Geometry, Point, Index, DimensionCount, DimensionCount > { static inline void apply(Geometry const&, Point&) { } }; template <typename Geometry> struct assign_2d_box_or_segment { typedef typename coordinate_type<Geometry>::type coordinate_type; // Here we assign 4 coordinates to a box of segment // -> Most logical is: x1,y1,x2,y2 // In case the user reverses x1/x2 or y1/y2, for a box, we could reverse them (THAT IS NOT IMPLEMENTED) template <typename Type> static inline void apply(Geometry& geometry, Type const& x1, Type const& y1, Type const& x2, Type const& y2) { geometry::set<0, 0>(geometry, boost::numeric_cast<coordinate_type>(x1)); geometry::set<0, 1>(geometry, boost::numeric_cast<coordinate_type>(y1)); geometry::set<1, 0>(geometry, boost::numeric_cast<coordinate_type>(x2)); geometry::set<1, 1>(geometry, boost::numeric_cast<coordinate_type>(y2)); } }; }} // namespace detail::assign #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename GeometryTag, typename Geometry, std::size_t DimensionCount> struct assign { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for this Geometry type.", GeometryTag, Geometry, std::integral_constant<std::size_t, DimensionCount>); }; template <typename Point> struct assign<point_tag, Point, 2> { typedef typename coordinate_type<Point>::type coordinate_type; template <typename T> static inline void apply(Point& point, T const& c1, T const& c2) { set<0>(point, boost::numeric_cast<coordinate_type>(c1)); set<1>(point, boost::numeric_cast<coordinate_type>(c2)); } }; template <typename Point> struct assign<point_tag, Point, 3> { typedef typename coordinate_type<Point>::type coordinate_type; template <typename T> static inline void apply(Point& point, T const& c1, T const& c2, T const& c3) { set<0>(point, boost::numeric_cast<coordinate_type>(c1)); set<1>(point, boost::numeric_cast<coordinate_type>(c2)); set<2>(point, boost::numeric_cast<coordinate_type>(c3)); } }; template <typename Box> struct assign<box_tag, Box, 2> : detail::assign::assign_2d_box_or_segment<Box> {}; template <typename Segment> struct assign<segment_tag, Segment, 2> : detail::assign::assign_2d_box_or_segment<Segment> {}; template <typename GeometryTag, typename Geometry> struct assign_zero {}; template <typename Point> struct assign_zero<point_tag, Point> : detail::assign::assign_zero_point {}; template <typename Box> struct assign_zero<box_tag, Box> : detail::assign::assign_zero_box_or_segment {}; template <typename Segment> struct assign_zero<segment_tag, Segment> : detail::assign::assign_zero_box_or_segment {}; template <typename GeometryTag, typename Geometry> struct assign_inverse {}; template <typename Box> struct assign_inverse<box_tag, Box> : detail::assign::assign_inverse_box_or_segment {}; template <typename Segment> struct assign_inverse<segment_tag, Segment> : detail::assign::assign_inverse_box_or_segment {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP detail/buffer/buffer_box.hpp 0000644 00000003725 15125631657 0012133 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2018-2019 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP #include <cstddef> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/access.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N> struct box_loop { typedef typename coordinate_type<BoxOut>::type coordinate_type; static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out) { coordinate_type d = distance; set<C, D>(box_out, get<C, D>(box_in) + d); box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out); } }; template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N> struct box_loop<BoxIn, BoxOut, T, C, N, N> { static inline void apply(BoxIn const&, T const&, BoxOut&) {} }; // Extends a box with the same amount in all directions template<typename BoxIn, typename BoxOut, typename T> inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out) { assert_dimension_equal<BoxIn, BoxOut>(); static const std::size_t N = dimension<BoxIn>::value; box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out); box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out); } }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP detail/buffer/turn_in_original_visitor.hpp 0000644 00000020753 15125631657 0015133 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2016, 2018. // Modifications copyright (c) 2016-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR #include <boost/core/ignore_unused.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp> #include <boost/geometry/strategies/buffer.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { struct original_get_box { template <typename Box, typename Original> static inline void apply(Box& total, Original const& original) { assert_coordinate_type_equal(total, original.m_box); typedef typename strategy::expand::services::default_strategy < box_tag, typename cs_tag<Box>::type >::type expand_strategy_type; geometry::expand(total, original.m_box, expand_strategy_type()); } }; template <typename DisjointBoxBoxStrategy> struct original_overlaps_box { template <typename Box, typename Original> static inline bool apply(Box const& box, Original const& original) { assert_coordinate_type_equal(box, original.m_box); return ! detail::disjoint::disjoint_box_box(box, original.m_box, DisjointBoxBoxStrategy()); } }; struct include_turn_policy { template <typename Turn> static inline bool apply(Turn const& turn) { return turn.is_turn_traversable; } }; template <typename DisjointPointBoxStrategy> struct turn_in_original_overlaps_box { template <typename Box, typename Turn> static inline bool apply(Box const& box, Turn const& turn) { if (! turn.is_turn_traversable || turn.within_original) { // Skip all points already processed return false; } return ! geometry::detail::disjoint::disjoint_point_box( turn.point, box, DisjointPointBoxStrategy()); } }; //! Check if specified is in range of specified iterators //! Return value of strategy (true if we can bail out) template < typename Strategy, typename State, typename Point, typename Iterator > inline bool point_in_range(Strategy& strategy, State& state, Point const& point, Iterator begin, Iterator end) { boost::ignore_unused(strategy); Iterator it = begin; for (Iterator previous = it++; it != end; ++previous, ++it) { if (! strategy.apply(point, *previous, *it, state)) { // We're probably on the boundary return false; } } return true; } template < typename Strategy, typename State, typename Point, typename CoordinateType, typename Iterator > inline bool point_in_section(Strategy& strategy, State& state, Point const& point, CoordinateType const& point_x, Iterator begin, Iterator end, int direction) { if (direction == 0) { // Not a monotonic section, or no change in X-direction return point_in_range(strategy, state, point, begin, end); } // We're in a monotonic section in x-direction Iterator it = begin; for (Iterator previous = it++; it != end; ++previous, ++it) { // Depending on sections.direction we can quit for this section CoordinateType const previous_x = geometry::get<0>(*previous); if (direction == 1 && point_x < previous_x) { // Section goes upwards, x increases, point is is below section return true; } else if (direction == -1 && point_x > previous_x) { // Section goes downwards, x decreases, point is above section return true; } if (! strategy.apply(point, *previous, *it, state)) { // We're probably on the boundary return false; } } return true; } template <typename Point, typename Original, typename PointInGeometryStrategy> inline int point_in_original(Point const& point, Original const& original, PointInGeometryStrategy const& strategy) { typename PointInGeometryStrategy::state_type state; if (boost::size(original.m_sections) == 0 || boost::size(original.m_ring) - boost::size(original.m_sections) < 16) { // There are no sections, or it does not profit to walk over sections // instead of over points. Boundary of 16 is arbitrary but can influence // performance point_in_range(strategy, state, point, original.m_ring.begin(), original.m_ring.end()); return strategy.result(state); } typedef typename Original::sections_type sections_type; typedef typename boost::range_iterator<sections_type const>::type iterator_type; typedef typename boost::range_value<sections_type const>::type section_type; typedef typename geometry::coordinate_type<Point>::type coordinate_type; coordinate_type const point_x = geometry::get<0>(point); // Walk through all monotonic sections of this original for (iterator_type it = boost::begin(original.m_sections); it != boost::end(original.m_sections); ++it) { section_type const& section = *it; if (! section.duplicate && section.begin_index < section.end_index && point_x >= geometry::get<min_corner, 0>(section.bounding_box) && point_x <= geometry::get<max_corner, 0>(section.bounding_box)) { // x-coordinate of point overlaps with section if (! point_in_section(strategy, state, point, point_x, boost::begin(original.m_ring) + section.begin_index, boost::begin(original.m_ring) + section.end_index + 1, section.directions[0])) { // We're probably on the boundary break; } } } return strategy.result(state); } template <typename Turns, typename PointInGeometryStrategy> class turn_in_original_visitor { public: turn_in_original_visitor(Turns& turns, PointInGeometryStrategy const& strategy) : m_mutable_turns(turns) , m_point_in_geometry_strategy(strategy) {} template <typename Turn, typename Original> inline bool apply(Turn const& turn, Original const& original) { if (boost::empty(original.m_ring)) { // Skip empty rings return true; } if (! turn.is_turn_traversable || turn.within_original) { // Skip all points already processed return true; } if (geometry::disjoint(turn.point, original.m_box)) { // Skip all disjoint return true; } int const code = point_in_original(turn.point, original, m_point_in_geometry_strategy); if (code == -1) { return true; } Turn& mutable_turn = m_mutable_turns[turn.turn_index]; if (code == 0) { // On border of original: always discard mutable_turn.is_turn_traversable = false; } // Point is inside an original ring if (original.m_is_interior) { mutable_turn.count_in_original--; } else if (original.m_has_interiors) { mutable_turn.count_in_original++; } else { // It is an exterior ring and there are no interior rings. // Then we are completely ready with this turn mutable_turn.within_original = true; mutable_turn.count_in_original = 1; } return true; } private : Turns& m_mutable_turns; PointInGeometryStrategy const& m_point_in_geometry_strategy; }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR detail/buffer/buffer_policies.hpp 0000644 00000020565 15125631657 0013153 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP #include <cstddef> #include <boost/range/value_type.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/strategies/buffer.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { class backtrack_for_buffer { public : typedef detail::overlay::backtrack_state state_type; template < typename Operation, typename Rings, typename Turns, typename Geometry, typename Strategy, typename RobustPolicy, typename Visitor > static inline void apply(std::size_t size_at_start, Rings& rings, typename boost::range_value<Rings>::type& ring, Turns& turns, typename boost::range_value<Turns>::type const& /*turn*/, Operation& operation, detail::overlay::traverse_error_type /*traverse_error*/, Geometry const& , Geometry const& , Strategy const& , RobustPolicy const& , state_type& state, Visitor& /*visitor*/ ) { #if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS) extern int g_backtrack_warning_count; g_backtrack_warning_count++; #endif //std::cout << "!"; //std::cout << "WARNING " << traverse_error_string(traverse_error) << std::endl; state.m_good = false; // Make bad output clean rings.resize(size_at_start); ring.clear(); // Reject this as a starting point operation.visited.set_rejected(); // And clear all visit info clear_visit_info(turns); } }; struct buffer_overlay_visitor { public : void print(char const* /*header*/) { } template <typename Turns> void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/) { } template <typename Turns> void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/, int /*op_index*/) { } template <typename Turns> void visit_turns(int , Turns const& ) {} template <typename Clusters, typename Turns> void visit_clusters(Clusters const& , Turns const& ) {} template <typename Turns, typename Turn, typename Operation> void visit_traverse(Turns const& /*turns*/, Turn const& /*turn*/, Operation const& /*op*/, const char* /*header*/) { } template <typename Turns, typename Turn, typename Operation> void visit_traverse_reject(Turns const& , Turn const& , Operation const& , detail::overlay::traverse_error_type ) {} template <typename Rings> void visit_generated_rings(Rings const& ) {} }; // Should follow traversal-turn-concept (enrichment, visit structure) // and adds index in piece vector to find it back template <typename Point, typename SegmentRatio> struct buffer_turn_operation : public detail::overlay::traversal_turn_operation<Point, SegmentRatio> { signed_size_type piece_index; signed_size_type index_in_robust_ring; inline buffer_turn_operation() : piece_index(-1) , index_in_robust_ring(-1) {} }; // Version of turn_info for buffer with its turn index and other helper variables template <typename Point, typename SegmentRatio> struct buffer_turn_info : public detail::overlay::turn_info < Point, SegmentRatio, buffer_turn_operation<Point, SegmentRatio> > { typedef Point point_type; std::size_t turn_index; // Information if turn can be used. It is not traversable if it is within // another piece, or within the original (depending on deflation), // or (for deflate) if there are not enough points to traverse it. bool is_turn_traversable; bool close_to_offset; bool is_linear_end_point; bool within_original; signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring inline buffer_turn_info() : turn_index(0) , is_turn_traversable(true) , close_to_offset(false) , is_linear_end_point(false) , within_original(false) , count_in_original(0) {} }; struct buffer_less { template <typename Indexed> inline bool operator()(Indexed const& left, Indexed const& right) const { if (! (left.subject->seg_id == right.subject->seg_id)) { return left.subject->seg_id < right.subject->seg_id; } // Both left and right are located on the SAME segment. if (! (left.subject->fraction == right.subject->fraction)) { return left.subject->fraction < right.subject->fraction; } return left.turn_index < right.turn_index; } }; struct piece_get_box { template <typename Box, typename Piece> static inline void apply(Box& total, Piece const& piece) { assert_coordinate_type_equal(total, piece.m_piece_border.m_envelope); typedef typename strategy::expand::services::default_strategy < box_tag, typename cs_tag<Box>::type >::type expand_strategy_type; if (piece.m_piece_border.m_has_envelope) { geometry::expand(total, piece.m_piece_border.m_envelope, expand_strategy_type()); } } }; template <typename DisjointBoxBoxStrategy> struct piece_overlaps_box { template <typename Box, typename Piece> static inline bool apply(Box const& box, Piece const& piece) { assert_coordinate_type_equal(box, piece.m_piece_border.m_envelope); if (piece.type == strategy::buffer::buffered_flat_end || piece.type == strategy::buffer::buffered_concave) { // Turns cannot be inside a flat end (though they can be on border) // Neither we need to check if they are inside concave helper pieces // Skip all pieces not used as soon as possible return false; } if (! piece.m_piece_border.m_has_envelope) { return false; } return ! geometry::detail::disjoint::disjoint_box_box(box, piece.m_piece_border.m_envelope, DisjointBoxBoxStrategy()); } }; struct turn_get_box { template <typename Box, typename Turn> static inline void apply(Box& total, Turn const& turn) { typedef typename strategy::expand::services::default_strategy < point_tag, typename cs_tag<Box>::type >::type expand_strategy_type; assert_coordinate_type_equal(total, turn.point); geometry::expand(total, turn.point, expand_strategy_type()); } }; template <typename DisjointPointBoxStrategy> struct turn_overlaps_box { template <typename Box, typename Turn> static inline bool apply(Box const& box, Turn const& turn) { assert_coordinate_type_equal(turn.point, box); return ! geometry::detail::disjoint::disjoint_point_box(turn.point, box, DisjointPointBoxStrategy()); } }; struct enriched_map_buffer_include_policy { template <typename Operation> static inline bool include(Operation const& op) { return op != detail::overlay::operation_intersection && op != detail::overlay::operation_blocked; } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP detail/buffer/piece_border.hpp 0000644 00000044250 15125631657 0012432 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP #include <boost/array.hpp> #include <boost/core/addressof.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/config.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/comparable_distance.hpp> #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp> #include <boost/geometry/strategies/cartesian/turn_in_ring_winding.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/geometries/segment.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename It, typename T, typename Compare> inline bool get_range_around(It begin, It end, T const& value, Compare const& compare, It& lower, It& upper) { lower = end; upper = end; // Get first element not smaller than value if (begin == end) { return false; } if (compare(value, *begin)) { // The value is smaller than the first item, therefore not in range return false; } // *(begin + std::distance(begin, end) - 1)) if (compare(*(end - 1), value)) { // The last item is larger than the value, therefore not in range return false; } // Assign the iterators. // lower >= begin and lower < end // upper > lower and upper <= end // lower_bound points to first element NOT LESS than value - but because // we want the first value LESS than value, we decrease it lower = std::lower_bound(begin, end, value, compare); // upper_bound points to first element of which value is LESS upper = std::upper_bound(begin, end, value, compare); if (lower != begin) { --lower; } if (upper != end) { ++upper; } return true; } } namespace detail { namespace buffer { //! Contains the border of the piece, consisting of 4 parts: //! 1: the part of the offsetted ring (referenced, not copied) //! 2: the part of the original (one or two points) //! 3: the left part (from original to offsetted) //! 4: the right part (from offsetted to original) //! Besides that, it contains some properties of the piece(border); //! - convexity //! - envelope //! - monotonicity of the offsetted ring //! - min/max radius of a point buffer //! - if it is a "reversed" piece (linear features with partly negative buffers) template <typename Ring, typename Point> struct piece_border { typedef typename geometry::coordinate_type<Point>::type coordinate_type; typedef typename default_comparable_distance_result<Point>::type radius_type; typedef typename geometry::strategy::buffer::turn_in_ring_winding<coordinate_type>::state_type state_type; bool m_reversed; // Points from the offsetted ring. They are not copied, this structure // refers to those points Ring const* m_ring; std::size_t m_begin; std::size_t m_end; // Points from the original (one or two, depending on piece shape) // Note, if there are 2 points, they are REVERSED w.r.t. the original // Therefore here we can walk in its order. boost::array<Point, 2> m_originals; std::size_t m_original_size; geometry::model::box<Point> m_envelope; bool m_has_envelope; // True if piece is determined as "convex" bool m_is_convex; // True if offsetted part is monotonically changing in x-direction bool m_is_monotonic_increasing; bool m_is_monotonic_decreasing; radius_type m_min_comparable_radius; radius_type m_max_comparable_radius; piece_border() : m_reversed(false) , m_ring(NULL) , m_begin(0) , m_end(0) , m_original_size(0) , m_has_envelope(false) , m_is_convex(false) , m_is_monotonic_increasing(false) , m_is_monotonic_decreasing(false) , m_min_comparable_radius(0) , m_max_comparable_radius(0) { } // Only used for debugging (SVG) Ring get_full_ring() const { Ring result; if (ring_or_original_empty()) { return result; } std::copy(m_ring->begin() + m_begin, m_ring->begin() + m_end, std::back_inserter(result)); std::copy(m_originals.begin(), m_originals.begin() + m_original_size, std::back_inserter(result)); // Add the closing point result.push_back(*(m_ring->begin() + m_begin)); return result; } void get_properties_of_border(bool is_point_buffer, Point const& center) { m_has_envelope = calculate_envelope(m_envelope); if (m_has_envelope) { // Take roundings into account, enlarge box geometry::detail::expand_by_epsilon(m_envelope); } if (! ring_or_original_empty() && is_point_buffer) { // Determine min/max radius calculate_radii(center, m_ring->begin() + m_begin, m_ring->begin() + m_end); } } template <typename SideStrategy> void get_properties_of_offsetted_ring_part(SideStrategy const& strategy) { if (! ring_or_original_empty()) { m_is_convex = is_convex(strategy); check_monotonicity(m_ring->begin() + m_begin, m_ring->begin() + m_end); } } void set_offsetted(Ring const& ring, std::size_t begin, std::size_t end) { BOOST_GEOMETRY_ASSERT(begin <= end); BOOST_GEOMETRY_ASSERT(begin < boost::size(ring)); BOOST_GEOMETRY_ASSERT(end <= boost::size(ring)); m_ring = boost::addressof(ring); m_begin = begin; m_end = end; } void add_original_point(Point const& point) { BOOST_GEOMETRY_ASSERT(m_original_size < 2); m_originals[m_original_size++] = point; } template <typename Box> bool calculate_envelope(Box& envelope) const { geometry::assign_inverse(envelope); if (ring_or_original_empty()) { return false; } expand_envelope(envelope, m_ring->begin() + m_begin, m_ring->begin() + m_end); expand_envelope(envelope, m_originals.begin(), m_originals.begin() + m_original_size); return true; } // Whatever the return value, the state should be checked. template <typename TurnPoint, typename State> bool point_on_piece(TurnPoint const& point, bool one_sided, bool is_linear_end_point, State& state) const { if (ring_or_original_empty()) { return false; } // Walk over the different parts of the ring, in clockwise order // For performance reasons: start with the helper part (one segment) // then the original part (one segment, if any), then the other helper // part (one segment), and only then the offsetted part // (probably more segments, check monotonicity) geometry::strategy::buffer::turn_in_ring_winding<coordinate_type> tir; Point const offsetted_front = *(m_ring->begin() + m_begin); Point const offsetted_back = *(m_ring->begin() + m_end - 1); // For onesided buffers, or turns colocated with linear end points, // the place on the ring is changed to offsetted (because of colocation) geometry::strategy::buffer::place_on_ring_type const por_original = adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_original, one_sided, is_linear_end_point); geometry::strategy::buffer::place_on_ring_type const por_from_offsetted = adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_from_offsetted, one_sided, is_linear_end_point); geometry::strategy::buffer::place_on_ring_type const por_to_offsetted = adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_to_offsetted, one_sided, is_linear_end_point); bool continue_processing = true; if (m_original_size == 1) { // One point. Walk from last offsetted to point, and from point to first offsetted continue_processing = step(point, offsetted_back, m_originals[0], tir, por_from_offsetted, state) && step(point, m_originals[0], offsetted_front, tir, por_to_offsetted, state); } else if (m_original_size == 2) { // Two original points. Walk from last offsetted point to first original point, // then along original, then from second oginal to first offsetted point continue_processing = step(point, offsetted_back, m_originals[0], tir, por_from_offsetted, state) && step(point, m_originals[0], m_originals[1], tir, por_original, state) && step(point, m_originals[1], offsetted_front, tir, por_to_offsetted, state); } if (continue_processing) { // Check the offsetted ring (in rounded joins, these might be // several segments) walk_offsetted(point, m_ring->begin() + m_begin, m_ring->begin() + m_end, tir, state); } return true; } //! Returns true if empty (no ring, or no points, or no original) bool ring_or_original_empty() const { return m_ring == NULL || m_begin >= m_end || m_original_size == 0; } private : static geometry::strategy::buffer::place_on_ring_type adapted_place_on_ring(geometry::strategy::buffer::place_on_ring_type target, bool one_sided, bool is_linear_end_point) { return one_sided || is_linear_end_point ? geometry::strategy::buffer::place_on_ring_offsetted : target; } template <typename TurnPoint, typename Iterator, typename Strategy, typename State> bool walk_offsetted(TurnPoint const& point, Iterator begin, Iterator end, Strategy const & strategy, State& state) const { Iterator it = begin; Iterator beyond = end; // Move iterators if the offsetted ring is monotonic increasing or decreasing if (m_is_monotonic_increasing) { if (! get_range_around(begin, end, point, geometry::less<Point, 0>(), it, beyond)) { return true; } } else if (m_is_monotonic_decreasing) { if (! get_range_around(begin, end, point, geometry::greater<Point, 0>(), it, beyond)) { return true; } } for (Iterator previous = it++ ; it != beyond ; ++previous, ++it ) { if (! step(point, *previous, *it, strategy, geometry::strategy::buffer::place_on_ring_offsetted, state)) { return false; } } return true; } template <typename TurnPoint, typename Strategy, typename State> bool step(TurnPoint const& point, Point const& p1, Point const& p2, Strategy const & strategy, geometry::strategy::buffer::place_on_ring_type place_on_ring, State& state) const { // A step between original/offsetted ring is always convex // (unless the join strategy generates points left of it - // future: convexity might be added to the buffer-join-strategy) // Therefore, if the state count > 0, it means the point is left of it, // and because it is convex, we can stop typedef typename geometry::coordinate_type<Point>::type coordinate_type; typedef geometry::detail::distance_measure<coordinate_type> dm_type; dm_type const dm = geometry::detail::get_distance_measure(point, p1, p2); if (m_is_convex && dm.measure > 0) { // The point is left of this segment of a convex piece state.m_count = 0; return false; } // Call strategy, and if it is on the border, return false // to stop further processing. return strategy.apply(point, p1, p2, dm, place_on_ring, state); } template <typename It, typename Box> void expand_envelope(Box& envelope, It begin, It end) const { typedef typename strategy::expand::services::default_strategy < point_tag, typename cs_tag<Box>::type >::type expand_strategy_type; for (It it = begin; it != end; ++it) { geometry::expand(envelope, *it, expand_strategy_type()); } } template <typename SideStrategy> bool is_convex(SideStrategy const& strategy) const { if (ring_or_original_empty()) { // Convexity is undetermined, and for this case it does not matter, // because it is only used for optimization in point_on_piece, // but that is not called if the piece border is not valid return false; } if (m_end - m_begin <= 2) { // The offsetted ring part of this piece has only two points. // If this is true, and the original ring part has only one point, // a triangle and it is convex. If the original ring part has two // points, it is a rectangle and theoretically could be concave, // but because of the way the buffer is generated, that is never // the case. return true; } // The offsetted ring part of thie piece has at least three points // (this is often the case in a piece marked as "join") // We can assume all points of the offset ring are different, and also // that all points on the original are different, and that the offsetted // ring is different from the original(s) Point const offsetted_front = *(m_ring->begin() + m_begin); Point const offsetted_second = *(m_ring->begin() + m_begin + 1); // These two points will be reassigned in every is_convex call Point previous = offsetted_front; Point current = offsetted_second; // Verify the offsetted range (from the second point on), the original, // and loop through the first two points of the offsetted range bool const result = is_convex(previous, current, m_ring->begin() + m_begin + 2, m_ring->begin() + m_end, strategy) && is_convex(previous, current, m_originals.begin(), m_originals.begin() + m_original_size, strategy) && is_convex(previous, current, offsetted_front, strategy) && is_convex(previous, current, offsetted_second, strategy); return result; } template <typename It, typename SideStrategy> bool is_convex(Point& previous, Point& current, It begin, It end, SideStrategy const& strategy) const { for (It it = begin; it != end; ++it) { if (! is_convex(previous, current, *it, strategy)) { return false; } } return true; } template <typename SideStrategy> bool is_convex(Point& previous, Point& current, Point const& next, SideStrategy const& strategy) const { typename SideStrategy::equals_point_point_strategy_type const eq_pp_strategy = strategy.get_equals_point_point_strategy(); int const side = strategy.apply(previous, current, next); if (side == 1) { // Next is on the left side of clockwise ring: piece is not convex return false; } if (! equals::equals_point_point(current, next, eq_pp_strategy)) { previous = current; current = next; } return true; } template <int Direction> inline void step_for_monotonicity(Point const& current, Point const& next) { if (geometry::get<Direction>(current) >= geometry::get<Direction>(next)) { m_is_monotonic_increasing = false; } if (geometry::get<Direction>(current) <= geometry::get<Direction>(next)) { m_is_monotonic_decreasing = false; } } template <typename It> void check_monotonicity(It begin, It end) { m_is_monotonic_increasing = true; m_is_monotonic_decreasing = true; if (begin == end || begin + 1 == end) { return; } It it = begin; for (It previous = it++; it != end; ++previous, ++it) { step_for_monotonicity<0>(*previous, *it); } } template <typename It> inline void calculate_radii(Point const& center, It begin, It end) { typedef geometry::model::referring_segment<Point const> segment_type; bool first = true; // An offsetted point-buffer ring around a point is supposed to be closed, // therefore walking from start to end is fine. It it = begin; for (It previous = it++; it != end; ++previous, ++it) { Point const& p0 = *previous; Point const& p1 = *it; segment_type const s(p0, p1); radius_type const d = geometry::comparable_distance(center, s); if (first || d < m_min_comparable_radius) { m_min_comparable_radius = d; } if (first || d > m_max_comparable_radius) { m_max_comparable_radius = d; } first = false; } } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PIECE_BORDER_HPP detail/buffer/turn_in_piece_visitor.hpp 0000644 00000015463 15125631657 0014416 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2016, 2018. // Modifications copyright (c) 2016-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/config.hpp> #include <boost/geometry/algorithms/comparable_distance.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/geometries/box.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { template < typename CsTag, typename Turns, typename Pieces, typename DistanceStrategy > class turn_in_piece_visitor { Turns& m_turns; // because partition is currently operating on const input only Pieces const& m_pieces; // to check for piece-type DistanceStrategy const& m_distance_strategy; // to check if point is on original or one_sided template <typename Operation, typename Piece> inline bool skip(Operation const& op, Piece const& piece) const { if (op.piece_index == piece.index) { return true; } Piece const& pc = m_pieces[op.piece_index]; if (pc.left_index == piece.index || pc.right_index == piece.index) { if (pc.type == strategy::buffer::buffered_flat_end) { // If it is a flat end, don't compare against its neighbor: // it will always be located on one of the helper segments return true; } if (pc.type == strategy::buffer::buffered_concave) { // If it is concave, the same applies: the IP will be // located on one of the helper segments return true; } } return false; } template <typename NumericType> inline bool is_one_sided(NumericType const& left, NumericType const& right) const { static NumericType const zero = 0; return geometry::math::equals(left, zero) || geometry::math::equals(right, zero); } template <typename Point> inline bool has_zero_distance_at(Point const& point) const { return is_one_sided(m_distance_strategy.apply(point, point, strategy::buffer::buffer_side_left), m_distance_strategy.apply(point, point, strategy::buffer::buffer_side_right)); } public: inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces, DistanceStrategy const& distance_strategy) : m_turns(turns) , m_pieces(pieces) , m_distance_strategy(distance_strategy) {} template <typename Turn, typename Piece> inline bool apply(Turn const& turn, Piece const& piece) { if (! turn.is_turn_traversable) { // Already handled return true; } if (piece.type == strategy::buffer::buffered_flat_end || piece.type == strategy::buffer::buffered_concave) { // Turns cannot be located within flat-end or concave pieces return true; } if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece)) { return true; } return apply(turn, piece, piece.m_piece_border); } template <typename Turn, typename Piece, typename Border> inline bool apply(Turn const& turn, Piece const& piece, Border const& border) { if (! geometry::covered_by(turn.point, border.m_envelope)) { // Easy check: if turn is not in the (expanded) envelope return true; } if (piece.type == geometry::strategy::buffer::buffered_point) { // Optimization for a buffer around points: if distance from center // is not between min/max radius, it is either inside or outside, // and more expensive checks are not necessary. typedef typename Border::radius_type radius_type; radius_type const d = geometry::comparable_distance(piece.m_center, turn.point); if (d < border.m_min_comparable_radius) { Turn& mutable_turn = m_turns[turn.turn_index]; mutable_turn.is_turn_traversable = false; return true; } if (d > border.m_max_comparable_radius) { return true; } } // Check if buffer is one-sided (at this point), because then a point // on the original is not considered as within. bool const one_sided = has_zero_distance_at(turn.point); typename Border::state_type state; if (! border.point_on_piece(turn.point, one_sided, turn.is_linear_end_point, state)) { return true; } if (state.code() == 1) { // It is WITHIN a piece, or on the piece border, but not // on the offsetted part of it. // TODO - at further removing rescaling, this threshold can be // adapted, or ideally, go. // This threshold is minimized to the point where fragile // unit tests of hard cases start to fail (5 in multi_polygon) // But it is acknowlegded that such a threshold depends on the // scale of the input. if (state.m_min_distance > 1.0e-5 || ! state.m_close_to_offset) { Turn& mutable_turn = m_turns[turn.turn_index]; mutable_turn.is_turn_traversable = false; // Keep track of the information if this turn was close // to an offset (without threshold). Because if it was, // it might have been classified incorrectly and in the // pretraversal step, it can in hindsight be classified // as "outside". mutable_turn.close_to_offset = state.m_close_to_offset; } } return true; } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP detail/buffer/buffer_inserter.hpp 0000644 00000106161 15125631657 0013174 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP #include <cstddef> #include <iterator> #include <boost/core/ignore_unused.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/rbegin.hpp> #include <boost/range/rend.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/direction_code.hpp> #include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp> #include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> #include <boost/geometry/algorithms/simplify.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/strategies/side.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/type_traits.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { template <typename Range, typename DistanceStrategy> inline void simplify_input(Range const& range, DistanceStrategy const& distance, Range& simplified) { // We have to simplify the ring before to avoid very small-scaled // features in the original (convex/concave/convex) being enlarged // in a very large scale and causing issues (IP's within pieces). // This might be reconsidered later. Simplifying with a very small // distance (1%% of the buffer) will never be visible in the result, // if it is using round joins. For miter joins they are even more // sensitive to small scale input features, however the result will // look better. // It also gets rid of duplicate points typedef typename geometry::point_type<Range>::type point_type; typedef typename strategy::distance::services::default_strategy < point_tag, segment_tag, point_type >::type ds_strategy_type; typedef strategy::simplify::douglas_peucker < point_type, ds_strategy_type > strategy_type; geometry::detail::simplify::simplify_range<2>::apply(range, simplified, distance.simplify_distance(), strategy_type()); } template <typename RingOutput> struct buffer_range { typedef typename point_type<RingOutput>::type output_point_type; typedef typename coordinate_type<RingOutput>::type coordinate_type; template < typename Collection, typename Point, typename DistanceStrategy, typename JoinStrategy, typename EndStrategy, typename RobustPolicy, typename SideStrategy > static inline void add_join(Collection& collection, Point const& penultimate_input, Point const& previous_input, output_point_type const& prev_perp1, output_point_type const& prev_perp2, Point const& input, output_point_type const& perp1, output_point_type const& perp2, geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& , SideStrategy const& side_strategy) { geometry::strategy::buffer::join_selector const join = get_join_type(penultimate_input, previous_input, input, side_strategy); switch(join) { case geometry::strategy::buffer::join_continue : // No join, we get two consecutive sides break; case geometry::strategy::buffer::join_concave : { std::vector<output_point_type> range_out; range_out.push_back(prev_perp2); range_out.push_back(previous_input); collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out); range_out.clear(); range_out.push_back(previous_input); range_out.push_back(perp1); collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out); } break; case geometry::strategy::buffer::join_spike : { // For linestrings, only add spike at one side to avoid // duplicates std::vector<output_point_type> range_out; end_strategy.apply(penultimate_input, prev_perp2, previous_input, perp1, side, distance, range_out); collection.add_endcap(end_strategy, range_out, previous_input); collection.set_current_ring_concave(); } break; case geometry::strategy::buffer::join_convex : { // The corner is convex, we create a join // TODO (future) - avoid a separate vector, add the piece directly output_point_type intersection_point; if (line_line_intersection::apply(perp1, perp2, prev_perp1, prev_perp2, intersection_point)) { std::vector<output_point_type> range_out; if (join_strategy.apply(intersection_point, previous_input, prev_perp2, perp1, distance.apply(previous_input, input, side), range_out)) { collection.add_piece(geometry::strategy::buffer::buffered_join, previous_input, range_out); } } } break; } } // Returns true if collinear point p2 continues after p0 and p1. // If it turns back (spike), it returns false. static inline bool same_direction(output_point_type const& p0, output_point_type const& p1, output_point_type const& p2) { typedef typename cs_tag<output_point_type>::type cs_tag; return direction_code<cs_tag>(p0, p1, p2) == 1; } template <typename SideStrategy> static inline geometry::strategy::buffer::join_selector get_join_type( output_point_type const& p0, output_point_type const& p1, output_point_type const& p2, SideStrategy const& side_strategy) { int const side = side_strategy.apply(p0, p1, p2); return side == -1 ? geometry::strategy::buffer::join_convex : side == 1 ? geometry::strategy::buffer::join_concave : same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue : geometry::strategy::buffer::join_spike; } template < typename Collection, typename Iterator, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename RobustPolicy, typename Strategy > static inline geometry::strategy::buffer::result_code iterate(Collection& collection, Iterator begin, Iterator end, geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& robust_policy, Strategy const& strategy, // side strategy bool linear, output_point_type& first_p1, output_point_type& first_p2, output_point_type& last_p1, output_point_type& last_p2) { boost::ignore_unused(side_strategy); typedef typename std::iterator_traits < Iterator >::value_type point_type; point_type second_point, penultimate_point, ultimate_point; // last two points from begin/end /* * last.p1 last.p2 these are the "previous (last) perpendicular points" * -------------- * | | * *------------*____ <- *prev * pup | | p1 "current perpendicular point 1" * | | * | | this forms a "side", a side is a piece * | | * *____| p2 * * ^ * *it * * pup: penultimate_point */ bool const mark_flat = linear && end_strategy.get_piece_type() == geometry::strategy::buffer::buffered_flat_end; geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output; bool first = true; Iterator it = begin; std::vector<output_point_type> generated_side; generated_side.reserve(2); for (Iterator prev = it++; it != end; ++it) { generated_side.clear(); geometry::strategy::buffer::result_code error_code = side_strategy.apply(*prev, *it, side, distance_strategy, generated_side); if (error_code == geometry::strategy::buffer::result_no_output) { // Because input is simplified, this is improbable, // but it can happen for degenerate geometries // Further handling of this side is skipped continue; } else if (error_code == geometry::strategy::buffer::result_error_numerical) { return error_code; } BOOST_GEOMETRY_ASSERT(! generated_side.empty()); result = geometry::strategy::buffer::result_normal; if (! first) { add_join(collection, penultimate_point, *prev, last_p1, last_p2, *it, generated_side.front(), generated_side.back(), side, distance_strategy, join_strategy, end_strategy, robust_policy, strategy); } collection.add_side_piece(*prev, *it, generated_side, first); if (first && mark_flat) { collection.mark_flat_start(*prev); } penultimate_point = *prev; ultimate_point = *it; last_p1 = generated_side.front(); last_p2 = generated_side.back(); prev = it; if (first) { first = false; second_point = *it; first_p1 = generated_side.front(); first_p2 = generated_side.back(); } } if (mark_flat) { collection.mark_flat_end(ultimate_point); } return result; } }; template < typename Multi, typename PolygonOutput, typename Policy > struct buffer_multi { template < typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline void apply(Multi const& multi, Collection& collection, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { for (typename boost::range_iterator<Multi const>::type it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, collection, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, strategy); } } }; struct visit_pieces_default_policy { template <typename Collection> static inline void apply(Collection const&, int) {} }; template < typename OutputPointType, typename Point, typename Collection, typename DistanceStrategy, typename PointStrategy > inline void buffer_point(Point const& point, Collection& collection, DistanceStrategy const& distance_strategy, PointStrategy const& point_strategy) { collection.start_new_ring(false); std::vector<OutputPointType> range_out; point_strategy.apply(point, distance_strategy, range_out); collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false); collection.set_piece_center(point); collection.finish_ring(geometry::strategy::buffer::result_normal); } }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Tag, typename RingInput, typename RingOutput > struct buffer_inserter {}; template < typename Point, typename RingOutput > struct buffer_inserter<point_tag, Point, RingOutput> { template < typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline void apply(Point const& point, Collection& collection, DistanceStrategy const& distance_strategy, SideStrategy const& , JoinStrategy const& , EndStrategy const& , PointStrategy const& point_strategy, RobustPolicy const& , Strategy const& ) // side strategy { detail::buffer::buffer_point < typename point_type<RingOutput>::type >(point, collection, distance_strategy, point_strategy); } }; // Not a specialization, but called from specializations of ring and of polygon. // Calling code starts/finishes ring before/after apply template < typename RingInput, typename RingOutput > struct buffer_inserter_ring { typedef typename point_type<RingOutput>::type output_point_type; template < typename Collection, typename Iterator, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename RobustPolicy, typename Strategy > static inline geometry::strategy::buffer::result_code iterate(Collection& collection, Iterator begin, Iterator end, geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { output_point_type first_p1, first_p2, last_p1, last_p2; typedef detail::buffer::buffer_range<RingOutput> buffer_range; geometry::strategy::buffer::result_code result = buffer_range::iterate(collection, begin, end, side, distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, strategy, false, first_p1, first_p2, last_p1, last_p2); // Generate closing join if (result == geometry::strategy::buffer::result_normal) { buffer_range::add_join(collection, *(end - 2), *(end - 1), last_p1, last_p2, *(begin + 1), first_p1, first_p2, side, distance_strategy, join_strategy, end_strategy, robust_policy, strategy); } // Buffer is closed automatically by last closing corner return result; } template < typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline geometry::strategy::buffer::result_code apply(RingInput const& ring, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { RingInput simplified; detail::buffer::simplify_input(ring, distance, simplified); geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output; std::size_t n = boost::size(simplified); std::size_t const min_points = core_detail::closure::minimum_ring_size < geometry::closure<RingInput>::value >::value; if (n >= min_points) { detail::normalized_view<RingInput const> view(simplified); if (distance.negative()) { // Walk backwards (rings will be reversed afterwards) code = iterate(collection, boost::rbegin(view), boost::rend(view), geometry::strategy::buffer::buffer_side_right, distance, side_strategy, join_strategy, end_strategy, robust_policy, strategy); } else { code = iterate(collection, boost::begin(view), boost::end(view), geometry::strategy::buffer::buffer_side_left, distance, side_strategy, join_strategy, end_strategy, robust_policy, strategy); } } if (code == geometry::strategy::buffer::result_no_output && n >= 1) { // Use point_strategy to buffer degenerated ring detail::buffer::buffer_point<output_point_type> ( geometry::range::front(simplified), collection, distance, point_strategy ); } return code; } }; template < typename RingInput, typename RingOutput > struct buffer_inserter<ring_tag, RingInput, RingOutput> { template < typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline geometry::strategy::buffer::result_code apply(RingInput const& ring, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { collection.start_new_ring(distance.negative()); geometry::strategy::buffer::result_code const code = buffer_inserter_ring<RingInput, RingOutput>::apply(ring, collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, strategy); collection.finish_ring(code, ring, false, false); return code; } }; template < typename Linestring, typename Polygon > struct buffer_inserter<linestring_tag, Linestring, Polygon> { typedef typename ring_type<Polygon>::type output_ring_type; typedef typename point_type<output_ring_type>::type output_point_type; typedef typename point_type<Linestring>::type input_point_type; template < typename Collection, typename Iterator, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename RobustPolicy, typename Strategy > static inline geometry::strategy::buffer::result_code iterate(Collection& collection, Iterator begin, Iterator end, geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& robust_policy, Strategy const& strategy, // side strategy output_point_type& first_p1) { input_point_type const& ultimate_point = *(end - 1); input_point_type const& penultimate_point = *(end - 2); // For the end-cap, we need to have the last perpendicular point on the // other side of the linestring. If it is the second pass (right), // we have it already from the first phase (left). // But for the first pass, we have to generate it output_point_type reverse_p1; if (side == geometry::strategy::buffer::buffer_side_right) { reverse_p1 = first_p1; } else { std::vector<output_point_type> generated_side; geometry::strategy::buffer::result_code code = side_strategy.apply(ultimate_point, penultimate_point, geometry::strategy::buffer::buffer_side_right, distance_strategy, generated_side); if (code != geometry::strategy::buffer::result_normal) { // No output or numerical error return code; } reverse_p1 = generated_side.front(); } output_point_type first_p2, last_p1, last_p2; geometry::strategy::buffer::result_code result = detail::buffer::buffer_range<output_ring_type>::iterate(collection, begin, end, side, distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, strategy, true, first_p1, first_p2, last_p1, last_p2); if (result == geometry::strategy::buffer::result_normal) { std::vector<output_point_type> range_out; end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out); collection.add_endcap(end_strategy, range_out, ultimate_point); } return result; } template < typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { Linestring simplified; detail::buffer::simplify_input(linestring, distance, simplified); geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output; std::size_t n = boost::size(simplified); if (n > 1) { collection.start_new_ring(false); output_point_type first_p1; code = iterate(collection, boost::begin(simplified), boost::end(simplified), geometry::strategy::buffer::buffer_side_left, distance, side_strategy, join_strategy, end_strategy, robust_policy, strategy, first_p1); if (code == geometry::strategy::buffer::result_normal) { code = iterate(collection, boost::rbegin(simplified), boost::rend(simplified), geometry::strategy::buffer::buffer_side_right, distance, side_strategy, join_strategy, end_strategy, robust_policy, strategy, first_p1); } collection.finish_ring(code); } if (code == geometry::strategy::buffer::result_no_output && n >= 1) { // Use point_strategy to buffer degenerated linestring detail::buffer::buffer_point<output_point_type> ( geometry::range::front(simplified), collection, distance, point_strategy ); } return code; } }; template < typename PolygonInput, typename PolygonOutput > struct buffer_inserter<polygon_tag, PolygonInput, PolygonOutput> { private: typedef typename ring_type<PolygonInput>::type input_ring_type; typedef typename ring_type<PolygonOutput>::type output_ring_type; typedef buffer_inserter_ring<input_ring_type, output_ring_type> policy; template < typename Iterator, typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline void iterate(Iterator begin, Iterator end, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy, // side strategy bool is_interior) { for (Iterator it = begin; it != end; ++it) { // For exterior rings, it deflates if distance is negative. // For interior rings, it is vice versa bool const deflate = is_interior ? ! distance.negative() : distance.negative(); collection.start_new_ring(deflate); geometry::strategy::buffer::result_code const code = policy::apply(*it, collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, strategy); collection.finish_ring(code, *it, is_interior, false); } } template < typename InteriorRings, typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline void apply_interior_rings(InteriorRings const& interior_rings, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { iterate(boost::begin(interior_rings), boost::end(interior_rings), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, strategy, true); } public: template < typename Collection, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename RobustPolicy, typename Strategy > static inline void apply(PolygonInput const& polygon, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { { collection.start_new_ring(distance.negative()); geometry::strategy::buffer::result_code const code = policy::apply(exterior_ring(polygon), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, strategy); collection.finish_ring(code, exterior_ring(polygon), false, geometry::num_interior_rings(polygon) > 0u); } apply_interior_rings(interior_rings(polygon), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, strategy); } }; template < typename Multi, typename PolygonOutput > struct buffer_inserter<multi_tag, Multi, PolygonOutput> : public detail::buffer::buffer_multi < Multi, PolygonOutput, dispatch::buffer_inserter < typename single_tag_of < typename tag<Multi>::type >::type, typename boost::range_value<Multi const>::type, typename geometry::ring_type<PolygonOutput>::type > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { template < typename GeometryOutput, typename GeometryInput, typename OutputIterator, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename IntersectionStrategy, typename RobustPolicy, typename VisitPiecesPolicy > inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, VisitPiecesPolicy& visit_pieces_policy ) { boost::ignore_unused(visit_pieces_policy); typedef detail::buffer::buffered_piece_collection < typename geometry::ring_type<GeometryOutput>::type, IntersectionStrategy, DistanceStrategy, RobustPolicy > collection_type; collection_type collection(intersection_strategy, distance_strategy, robust_policy); collection_type const& const_collection = collection; bool const areal = util::is_areal<GeometryInput>::value; dispatch::buffer_inserter < typename tag_cast < typename tag<GeometryInput>::type, multi_tag >::type, GeometryInput, GeometryOutput >::apply(geometry_input, collection, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, robust_policy, intersection_strategy.get_side_strategy()); collection.get_turns(); if (BOOST_GEOMETRY_CONDITION(areal)) { collection.check_turn_in_original(); } collection.verify_turns(); // Visit the piece collection. This does nothing (by default), but // optionally a debugging tool can be attached (e.g. console or svg), // or the piece collection can be unit-tested // phase 0: turns (before discarded) visit_pieces_policy.apply(const_collection, 0); collection.discard_rings(); collection.block_turns(); collection.enrich(); // phase 1: turns (after enrichment/clustering) visit_pieces_policy.apply(const_collection, 1); if (BOOST_GEOMETRY_CONDITION(areal)) { collection.deflate_check_turns(); } collection.traverse(); // Reverse all offsetted rings / traversed rings if: // - they were generated on the negative side (deflate) of polygons // - the output is counter clockwise // and avoid reversing twice bool reverse = distance_strategy.negative() && areal; if (BOOST_GEOMETRY_CONDITION( geometry::point_order<GeometryOutput>::value == counterclockwise)) { reverse = ! reverse; } if (reverse) { collection.reverse(); } if (BOOST_GEOMETRY_CONDITION(distance_strategy.negative() && areal)) { collection.discard_nonintersecting_deflated_rings(); } collection.template assign<GeometryOutput>(out); // Visit collection again // phase 2: rings (after traversing) visit_pieces_policy.apply(const_collection, 2); } template < typename GeometryOutput, typename GeometryInput, typename OutputIterator, typename DistanceStrategy, typename SideStrategy, typename JoinStrategy, typename EndStrategy, typename PointStrategy, typename IntersectionStrategy, typename RobustPolicy > inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) { detail::buffer::visit_pieces_default_policy visitor; buffer_inserter<GeometryOutput>(geometry_input, out, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, intersection_strategy, robust_policy, visitor); } #endif // DOXYGEN_NO_DETAIL }} // namespace detail::buffer }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_INSERTER_HPP detail/buffer/buffered_ring.hpp 0000644 00000015220 15125631657 0012604 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING #include <cstddef> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { struct buffered_ring_collection_tag : polygonal_tag, multi_tag {}; template <typename Ring> struct buffered_ring : public Ring { bool has_concave; bool has_accepted_intersections; bool has_discarded_intersections; bool is_untouched_outside_original; inline buffered_ring() : has_concave(false) , has_accepted_intersections(false) , has_discarded_intersections(false) , is_untouched_outside_original(false) {} inline bool discarded() const { return has_discarded_intersections && ! has_accepted_intersections; } inline bool has_intersections() const { return has_discarded_intersections || has_accepted_intersections; } }; // This is a collection now special for overlay (needs vector of rings) template <typename Ring> struct buffered_ring_collection : public std::vector<Ring> { }; }} // namespace detail::buffer // Turn off concept checking (for now) namespace dispatch { template <typename Geometry, bool IsConst> struct check<Geometry, detail::buffer::buffered_ring_collection_tag, IsConst> { }; } #endif // DOXYGEN_NO_DETAIL // Register the types namespace traits { template <typename Ring> struct tag<geometry::detail::buffer::buffered_ring<Ring> > { typedef ring_tag type; }; template <typename Ring> struct point_order<geometry::detail::buffer::buffered_ring<Ring> > { static const order_selector value = geometry::point_order<Ring>::value; }; template <typename Ring> struct closure<geometry::detail::buffer::buffered_ring<Ring> > { static const closure_selector value = geometry::closure<Ring>::value; }; template <typename Ring> struct point_type<geometry::detail::buffer::buffered_ring_collection<Ring> > { typedef typename geometry::point_type<Ring>::type type; }; template <typename Ring> struct tag<geometry::detail::buffer::buffered_ring_collection<Ring> > { typedef geometry::detail::buffer::buffered_ring_collection_tag type; }; } // namespace traits namespace core_dispatch { template <typename Ring> struct ring_type < detail::buffer::buffered_ring_collection_tag, detail::buffer::buffered_ring_collection<Ring> > { typedef Ring type; }; // There is a specific tag, so this specialization cannot be placed in traits template <typename Ring> struct point_order<detail::buffer::buffered_ring_collection_tag, geometry::detail::buffer::buffered_ring_collection < geometry::detail::buffer::buffered_ring<Ring> > > { static const order_selector value = core_dispatch::point_order<ring_tag, Ring>::value; }; } template <> struct single_tag_of<detail::buffer::buffered_ring_collection_tag> { typedef ring_tag type; }; namespace dispatch { template < typename MultiRing, bool Reverse, typename SegmentIdentifier, typename PointOut > struct copy_segment_point < detail::buffer::buffered_ring_collection_tag, MultiRing, Reverse, SegmentIdentifier, PointOut > : detail::copy_segments::copy_segment_point_multi < MultiRing, SegmentIdentifier, PointOut, detail::copy_segments::copy_segment_point_range < typename boost::range_value<MultiRing>::type, Reverse, SegmentIdentifier, PointOut > > {}; template<bool Reverse> struct copy_segments < detail::buffer::buffered_ring_collection_tag, Reverse > : detail::copy_segments::copy_segments_multi < detail::copy_segments::copy_segments_ring<Reverse> > {}; template <typename Point, typename MultiGeometry> struct within < Point, MultiGeometry, point_tag, detail::buffer::buffered_ring_collection_tag > { template <typename Strategy> static inline bool apply(Point const& point, MultiGeometry const& multi, Strategy const& strategy) { return detail::within::point_in_geometry(point, multi, strategy) == 1; } }; template <typename Geometry> struct is_empty<Geometry, detail::buffer::buffered_ring_collection_tag> : detail::is_empty::multi_is_empty<detail::is_empty::range_is_empty> {}; template <typename Geometry> struct envelope<Geometry, detail::buffer::buffered_ring_collection_tag> : detail::envelope::envelope_multi_range < detail::envelope::envelope_range > {}; } // namespace dispatch namespace detail { namespace overlay { template<> struct get_ring<detail::buffer::buffered_ring_collection_tag> { template<typename MultiGeometry> static inline typename ring_type<MultiGeometry>::type const& apply( ring_identifier const& id, MultiGeometry const& multi_ring) { BOOST_GEOMETRY_ASSERT ( id.multi_index >= 0 && id.multi_index < int(boost::size(multi_ring)) ); return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]); } }; }} }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING detail/buffer/buffered_piece_collection.hpp 0000644 00000126226 15125631657 0015156 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2016-2020. // Modifications copyright (c) 2016-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP #include <algorithm> #include <cstddef> #include <set> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/strategies/buffer.hpp> #include <boost/geometry/geometries/ring.hpp> #include <boost/geometry/algorithms/detail/buffer/buffered_ring.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp> #include <boost/geometry/algorithms/detail/buffer/piece_border.hpp> #include <boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp> #include <boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp> #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp> #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp> #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp> #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp> #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/traverse.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/views/detail/normalized_view.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { /* * Terminology * * Suppose we make a buffer (using blocked corners) of this rectangle: * * +-------+ * | | * | rect | * | | * +-------+ * * For the sides we get these four buffered side-pieces (marked with s) * and four buffered corner pieces (marked with c) * * c---+---s---+---c * | | piece | | <- see below for details of the middle top-side-piece * +---+-------+---+ * | | | | * s | rect | s <- two side pieces left/right of rect * | | | | * +---+-------+---+ * | | piece | | <- one side-piece below, and two corner pieces * c---+---s---+---c * * The outer part of the picture above, using all pieces, * form together the offsetted ring (marked with o below) * The 8 pieces are part of the piece collection and use for inside-checks * The inner parts form (using 1 or 2 points per piece, often co-located) * form together the robust_polygons (marked with r below) * The remaining piece-segments are helper-segments (marked with h) * * ooooooooooooooooo * o h h o * ohhhrrrrrrrrrhhho * o r r o * o r r o * o r r o * ohhhrrrrrrrrrhhho * o h h o * ooooooooooooooooo * */ template < typename Ring, typename IntersectionStrategy, typename DistanceStrategy, typename RobustPolicy > struct buffered_piece_collection { typedef typename geometry::point_type<Ring>::type point_type; typedef typename geometry::coordinate_type<Ring>::type coordinate_type; // Ring/polygon type, always clockwise typedef geometry::model::ring<point_type> clockwise_ring_type; typedef geometry::model::box<point_type> box_type; typedef typename IntersectionStrategy::side_strategy_type side_strategy_type; typedef typename IntersectionStrategy::envelope_strategy_type envelope_strategy_type; typedef typename IntersectionStrategy::expand_strategy_type expand_strategy_type; typedef typename IntersectionStrategy::template area_strategy < point_type >::type area_strategy_type; typedef typename area_strategy_type::template result_type < point_type >::type area_result_type; typedef typename IntersectionStrategy::template point_in_geometry_strategy < point_type, clockwise_ring_type >::type point_in_geometry_strategy_type; typedef buffer_turn_info < point_type, typename segment_ratio_type<point_type, RobustPolicy>::type > buffer_turn_info_type; typedef buffer_turn_operation < point_type, typename segment_ratio_type<point_type, RobustPolicy>::type > buffer_turn_operation_type; typedef std::vector<buffer_turn_info_type> turn_vector_type; typedef piece_border<Ring, point_type> piece_border_type; struct piece { strategy::buffer::piece_type type; signed_size_type index; signed_size_type left_index; // points to previous piece of same ring signed_size_type right_index; // points to next piece of same ring // The next two members (1, 2) form together a complete clockwise ring // for each piece (with one dupped point) // The complete clockwise ring is also included as a robust ring (3) // 1: half, part of offsetted_rings // Segment identifier of this piece, including its start index segment_identifier first_seg_id; // One-beyond index of this piece, to iterate over a ring // from: ring.begin() + pc.first_seg_id.segment_index; // to (not including): ring.begin() + pc.beyond_last_segment_index; // Its ring_id etc are shared with first_seg_id signed_size_type beyond_last_segment_index; // part in offsetted ring which is part of offsetted ring signed_size_type offsetted_count; bool is_flat_start; bool is_flat_end; bool is_deflated; // Ring (parts) of this piece, always clockwise piece_border_type m_piece_border; point_type m_label_point; // For a point buffer point_type m_center; piece() : type(strategy::buffer::piece_type_unknown) , index(-1) , left_index(-1) , right_index(-1) , beyond_last_segment_index(-1) , offsetted_count(-1) , is_flat_start(false) , is_flat_end(false) , is_deflated(false) { } }; struct original_ring { typedef geometry::sections<box_type, 1> sections_type; // Creates an empty instance inline original_ring() : m_is_interior(false) , m_has_interiors(false) {} inline original_ring(clockwise_ring_type const& ring, bool is_interior, bool has_interiors, envelope_strategy_type const& envelope_strategy, expand_strategy_type const& expand_strategy) : m_ring(ring) , m_is_interior(is_interior) , m_has_interiors(has_interiors) { geometry::envelope(m_ring, m_box, envelope_strategy); // create monotonic sections in x-dimension // The dimension is critical because the direction is later used // in the optimization for within checks using winding strategy // and this strategy is scanning in x direction. typedef std::integer_sequence<std::size_t, 0> dimensions; geometry::sectionalize<false, dimensions>(m_ring, detail::no_rescale_policy(), m_sections, envelope_strategy, expand_strategy); } clockwise_ring_type m_ring; box_type m_box; sections_type m_sections; bool m_is_interior; bool m_has_interiors; }; typedef std::vector<piece> piece_vector_type; piece_vector_type m_pieces; turn_vector_type m_turns; signed_size_type m_first_piece_index; bool m_deflate; bool m_has_deflated; // Offsetted rings, and representations of original ring(s) // both indexed by multi_index buffered_ring_collection<buffered_ring<Ring> > offsetted_rings; std::vector<original_ring> original_rings; std::vector<point_type> m_linear_end_points; buffered_ring_collection<Ring> traversed_rings; segment_identifier current_segment_id; // Monotonic sections (used for offsetted rings around points) // are still using a robust type, to be comparable with turn calculations, // which is using rescaling. typedef geometry::model::box < typename geometry::robust_point_type<point_type, RobustPolicy>::type > robust_box_type; typedef geometry::sections <robust_box_type, 2> robust_sections_type; robust_sections_type monotonic_sections; // Define the clusters, mapping cluster_id -> turns typedef std::map < signed_size_type, detail::overlay::cluster_info > cluster_type; cluster_type m_clusters; IntersectionStrategy m_intersection_strategy; DistanceStrategy m_distance_strategy; side_strategy_type m_side_strategy; area_strategy_type m_area_strategy; envelope_strategy_type m_envelope_strategy; expand_strategy_type m_expand_strategy; point_in_geometry_strategy_type m_point_in_geometry_strategy; RobustPolicy const& m_robust_policy; buffered_piece_collection(IntersectionStrategy const& intersection_strategy, DistanceStrategy const& distance_strategy, RobustPolicy const& robust_policy) : m_first_piece_index(-1) , m_deflate(false) , m_has_deflated(false) , m_intersection_strategy(intersection_strategy) , m_distance_strategy(distance_strategy) , m_side_strategy(intersection_strategy.get_side_strategy()) , m_area_strategy(intersection_strategy .template get_area_strategy<point_type>()) , m_envelope_strategy(intersection_strategy.get_envelope_strategy()) , m_expand_strategy(intersection_strategy.get_expand_strategy()) , m_point_in_geometry_strategy(intersection_strategy .template get_point_in_geometry_strategy<point_type, clockwise_ring_type>()) , m_robust_policy(robust_policy) {} inline bool is_following(buffer_turn_info_type const& turn, buffer_turn_operation_type const& op) { return turn.operations[0].seg_id.segment_index == op.seg_id.segment_index || turn.operations[1].seg_id.segment_index == op.seg_id.segment_index; } // Verify if turns which are classified as OK (outside or on border of // offsetted ring) do not traverse through other turns which are classified // as WITHIN (inside a piece). This can happen if turns are nearly colocated // and due to floating point precision just classified as within, while // they should not be within. // In those cases the turns are fine to travel through (and should), // but they are not made startable. template <typename Vector> inline void pretraverse(Vector const& indexed_operations) { // Verify if the turns which are OK don't skip segments typedef typename boost::range_value<Vector>::type indexed_type; buffer_turn_operation_type last_traversable_operation; buffer_turn_info_type last_traversable_turn; bool first = true; for (std::size_t i = 0; i < indexed_operations.size(); i++) { indexed_type const & itop = indexed_operations[i]; buffer_turn_info_type const& turn = m_turns[itop.turn_index]; if (turn.is_turn_traversable && ! first) { // Check previous and next turns. The first is handled BOOST_GEOMETRY_ASSERT(i > 0); indexed_type const& previous_itop = indexed_operations[i - 1]; std::size_t const next_index = i + 1 < indexed_operations.size() ? i + 1 : 0; indexed_type const& next_itop = indexed_operations[next_index]; buffer_turn_info_type& previous_turn = m_turns[previous_itop.turn_index]; buffer_turn_info_type& next_turn = m_turns[next_itop.turn_index]; if (previous_turn.close_to_offset && is_following(previous_turn, last_traversable_operation)) { previous_turn.is_turn_traversable = true; } else if (next_turn.close_to_offset && is_following(next_turn, last_traversable_operation)) { next_turn.is_turn_traversable = true; } } if (turn.is_turn_traversable) { first = false; last_traversable_operation = *itop.subject; last_traversable_turn = turn; } } } inline void check_linear_endpoints(buffer_turn_info_type& turn) const { // TODO this is quadratic. But the #endpoints, expected, is low, // and only applicable for linear features // (in a multi linestring with many short lines, the #endpoints can be // much higher) for (typename boost::range_iterator<std::vector<point_type> const>::type it = boost::begin(m_linear_end_points); it != boost::end(m_linear_end_points); ++it) { if (detail::equals::equals_point_point(turn.point, *it, m_intersection_strategy.get_equals_point_point_strategy())) { turn.is_linear_end_point = true; } } } inline void verify_turns() { typedef detail::overlay::indexed_turn_operation < buffer_turn_operation_type > indexed_turn_operation; typedef std::map < ring_identifier, std::vector<indexed_turn_operation> > mapped_vector_type; mapped_vector_type mapped_vector; detail::overlay::create_map(m_turns, mapped_vector, enriched_map_buffer_include_policy()); // Sort turns over offsetted ring(s) for (typename mapped_vector_type::iterator mit = mapped_vector.begin(); mit != mapped_vector.end(); ++mit) { std::sort(mit->second.begin(), mit->second.end(), buffer_less()); } for (typename mapped_vector_type::iterator mit = mapped_vector.begin(); mit != mapped_vector.end(); ++mit) { pretraverse(mit->second); } } inline void deflate_check_turns() { if (! m_has_deflated) { return; } // Deflated rings may not travel to themselves, there should at least // be three turns (which cannot be checked here - TODO: add to traverse) for (typename boost::range_iterator<turn_vector_type>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { buffer_turn_info_type& turn = *it; if (! turn.is_turn_traversable) { continue; } for (int i = 0; i < 2; i++) { buffer_turn_operation_type& op = turn.operations[i]; if (op.enriched.get_next_turn_index() == static_cast<signed_size_type>(turn.turn_index) && m_pieces[op.seg_id.piece_index].is_deflated) { // Keep traversable, but don't start here op.enriched.startable = false; } } } } // Check if a turn is inside any of the originals inline void check_turn_in_original() { typedef turn_in_original_overlaps_box < typename IntersectionStrategy::disjoint_point_box_strategy_type > turn_in_original_overlaps_box_type; typedef original_overlaps_box < typename IntersectionStrategy::disjoint_box_box_strategy_type > original_overlaps_box_type; turn_in_original_visitor < turn_vector_type, point_in_geometry_strategy_type > visitor(m_turns, m_point_in_geometry_strategy); geometry::partition < box_type, include_turn_policy, detail::partition::include_all_policy >::apply(m_turns, original_rings, visitor, turn_get_box(), turn_in_original_overlaps_box_type(), original_get_box(), original_overlaps_box_type()); bool const deflate = m_distance_strategy.negative(); for (typename boost::range_iterator<turn_vector_type>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { buffer_turn_info_type& turn = *it; if (turn.is_turn_traversable) { if (deflate && turn.count_in_original <= 0) { // For deflate/negative buffers: // it is not in the original, so don't use it turn.is_turn_traversable = false; } else if (! deflate && turn.count_in_original > 0) { // For inflate: it is in original, so don't use it turn.is_turn_traversable = false; } } } } inline void update_turn_administration() { std::size_t index = 0; for (typename boost::range_iterator<turn_vector_type>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) { buffer_turn_info_type& turn = *it; // Update member used turn.turn_index = index; // Verify if a turn is a linear endpoint if (! turn.is_linear_end_point) { check_linear_endpoints(turn); } } } // Calculate properties of piece borders which are not influenced // by turns themselves: // - envelopes (essential for partitioning during calc turns) // - convexity // - monotonicity // - min/max radius of point buffers // - (if pieces are reversed) inline void update_piece_administration() { for (typename piece_vector_type::iterator it = boost::begin(m_pieces); it != boost::end(m_pieces); ++it) { piece& pc = *it; piece_border_type& border = pc.m_piece_border; buffered_ring<Ring> const& ring = offsetted_rings[pc.first_seg_id.multi_index]; if (pc.offsetted_count > 0) { if (pc.type != strategy::buffer::buffered_concave) { border.set_offsetted(ring, pc.first_seg_id.segment_index, pc.beyond_last_segment_index); } // Calculate envelopes for piece borders border.get_properties_of_border(pc.type == geometry::strategy::buffer::buffered_point, pc.m_center); if (! pc.is_flat_end && ! pc.is_flat_start) { border.get_properties_of_offsetted_ring_part(m_side_strategy); } } } } inline void get_turns() { update_piece_administration(); { // Calculate the turns piece_turn_visitor < piece_vector_type, buffered_ring_collection<buffered_ring<Ring> >, turn_vector_type, IntersectionStrategy, RobustPolicy > visitor(m_pieces, offsetted_rings, m_turns, m_intersection_strategy, m_robust_policy); typedef detail::section::get_section_box < typename IntersectionStrategy::expand_box_strategy_type > get_section_box_type; typedef detail::section::overlaps_section_box < typename IntersectionStrategy::disjoint_box_box_strategy_type > overlaps_section_box_type; detail::sectionalize::enlarge_sections(monotonic_sections, m_envelope_strategy); geometry::partition < robust_box_type >::apply(monotonic_sections, visitor, get_section_box_type(), overlaps_section_box_type()); } update_turn_administration(); { // Check if turns are inside pieces turn_in_piece_visitor < typename geometry::cs_tag<point_type>::type, turn_vector_type, piece_vector_type, DistanceStrategy > visitor(m_turns, m_pieces, m_distance_strategy); typedef turn_overlaps_box < typename IntersectionStrategy::disjoint_point_box_strategy_type > turn_overlaps_box_type; typedef piece_overlaps_box < typename IntersectionStrategy::disjoint_box_box_strategy_type > piece_overlaps_box_type; geometry::partition < box_type >::apply(m_turns, m_pieces, visitor, turn_get_box(), turn_overlaps_box_type(), piece_get_box(), piece_overlaps_box_type()); } } inline void start_new_ring(bool deflate) { std::size_t const n = offsetted_rings.size(); current_segment_id.source_index = 0; current_segment_id.multi_index = static_cast<signed_size_type>(n); current_segment_id.ring_index = -1; current_segment_id.segment_index = 0; offsetted_rings.resize(n + 1); original_rings.resize(n + 1); m_first_piece_index = static_cast<signed_size_type>(boost::size(m_pieces)); m_deflate = deflate; if (deflate) { // Pieces contain either deflated exterior rings, or inflated // interior rings which are effectively deflated too m_has_deflated = true; } } inline void abort_ring() { // Remove all created pieces for this ring, sections, last offsetted while (! m_pieces.empty() && m_pieces.back().first_seg_id.multi_index == current_segment_id.multi_index) { m_pieces.pop_back(); } offsetted_rings.pop_back(); original_rings.pop_back(); m_first_piece_index = -1; } inline void update_last_point(point_type const& p, buffered_ring<Ring>& ring) { // For the first point of a new piece, and there were already // points in the offsetted ring, for some piece types the first point // is a duplicate of the last point of the previous piece. // TODO: disable that, that point should not be added // For now, it is made equal because due to numerical instability, // it can be a tiny bit off, possibly causing a self-intersection BOOST_GEOMETRY_ASSERT(boost::size(m_pieces) > 0); if (! ring.empty() && current_segment_id.segment_index == m_pieces.back().first_seg_id.segment_index) { ring.back() = p; } } inline void set_piece_center(point_type const& center) { BOOST_GEOMETRY_ASSERT(! m_pieces.empty()); m_pieces.back().m_center = center; } inline bool finish_ring(strategy::buffer::result_code code) { if (code == strategy::buffer::result_error_numerical) { abort_ring(); return false; } if (m_first_piece_index == -1) { return false; } // Casted version std::size_t const first_piece_index = static_cast<std::size_t>(m_first_piece_index); signed_size_type const last_piece_index = static_cast<signed_size_type>(boost::size(m_pieces)) - 1; if (first_piece_index < boost::size(m_pieces)) { // If pieces were added, // reassign left-of-first and right-of-last geometry::range::at(m_pieces, first_piece_index).left_index = last_piece_index; geometry::range::back(m_pieces).right_index = m_first_piece_index; } buffered_ring<Ring>& added = offsetted_rings.back(); if (! boost::empty(added)) { // Make sure the closing point is identical (they are calculated // separately by different pieces) range::back(added) = range::front(added); } for (std::size_t i = first_piece_index; i < boost::size(m_pieces); i++) { sectionalize(m_pieces[i], added); } m_first_piece_index = -1; return true; } template <typename InputRing> inline void finish_ring(strategy::buffer::result_code code, InputRing const& input_ring, bool is_interior, bool has_interiors) { if (! finish_ring(code)) { return; } if (! input_ring.empty()) { // Assign the ring to the original_ring collection // For rescaling, it is recalculated. Without rescaling, it // is just assigning (note that this Ring type is the // GeometryOut type, which might differ from the input ring type) clockwise_ring_type clockwise_ring; typedef detail::normalized_view<InputRing const> view_type; view_type const view(input_ring); for (typename boost::range_iterator<view_type const>::type it = boost::begin(view); it != boost::end(view); ++it) { clockwise_ring.push_back(*it); } original_rings.back() = original_ring(clockwise_ring, is_interior, has_interiors, m_envelope_strategy, m_expand_strategy); } } inline void set_current_ring_concave() { BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0); offsetted_rings.back().has_concave = true; } inline signed_size_type add_point(point_type const& p) { BOOST_GEOMETRY_ASSERT(boost::size(offsetted_rings) > 0); buffered_ring<Ring>& current_ring = offsetted_rings.back(); update_last_point(p, current_ring); current_segment_id.segment_index++; current_ring.push_back(p); return static_cast<signed_size_type>(current_ring.size()); } //------------------------------------------------------------------------- inline piece& create_piece(strategy::buffer::piece_type type, bool decrease_segment_index_by_one) { if (type == strategy::buffer::buffered_concave) { offsetted_rings.back().has_concave = true; } piece pc; pc.type = type; pc.index = static_cast<signed_size_type>(boost::size(m_pieces)); pc.is_deflated = m_deflate; current_segment_id.piece_index = pc.index; pc.first_seg_id = current_segment_id; // Assign left/right (for first/last piece per ring they will be re-assigned later) pc.left_index = pc.index - 1; pc.right_index = pc.index + 1; std::size_t const n = boost::size(offsetted_rings.back()); pc.first_seg_id.segment_index = decrease_segment_index_by_one ? n - 1 : n; pc.beyond_last_segment_index = pc.first_seg_id.segment_index; m_pieces.push_back(pc); return m_pieces.back(); } inline void init_rescale_piece(piece& pc) { if (pc.first_seg_id.segment_index < 0) { // This indicates an error situation: an earlier piece was empty // It currently does not happen pc.offsetted_count = 0; return; } BOOST_GEOMETRY_ASSERT(pc.first_seg_id.multi_index >= 0); BOOST_GEOMETRY_ASSERT(pc.beyond_last_segment_index >= 0); pc.offsetted_count = pc.beyond_last_segment_index - pc.first_seg_id.segment_index; BOOST_GEOMETRY_ASSERT(pc.offsetted_count >= 0); } inline void add_piece_point(piece& pc, const point_type& point, bool add_to_original) { if (add_to_original && pc.type != strategy::buffer::buffered_concave) { pc.m_piece_border.add_original_point(point); } else { pc.m_label_point = point; } } inline void sectionalize(piece const& pc, buffered_ring<Ring> const& ring) { typedef geometry::detail::sectionalize::sectionalize_part < point_type, std::integer_sequence<std::size_t, 0, 1> // x,y dimension > sectionalizer; // Create a ring-identifier. The source-index is the piece index // The multi_index is as in this collection (the ring), but not used here // The ring_index is not used ring_identifier const ring_id(pc.index, pc.first_seg_id.multi_index, -1); sectionalizer::apply(monotonic_sections, boost::begin(ring) + pc.first_seg_id.segment_index, boost::begin(ring) + pc.beyond_last_segment_index, m_robust_policy, ring_id, 10); } inline void finish_piece(piece& pc) { init_rescale_piece(pc); } inline void finish_piece(piece& pc, point_type const& point1, point_type const& point2, point_type const& point3) { init_rescale_piece(pc); if (pc.offsetted_count == 0) { return; } add_piece_point(pc, point1, false); add_piece_point(pc, point2, true); add_piece_point(pc, point3, false); } inline void finish_piece(piece& pc, point_type const& point1, point_type const& point2, point_type const& point3, point_type const& point4) { init_rescale_piece(pc); // Add the four points. Note that points 2 and 3 are the originals, // and that they are already passed in reverse order // (because the offsetted ring is in clockwise order) add_piece_point(pc, point1, false); add_piece_point(pc, point2, true); add_piece_point(pc, point3, true); add_piece_point(pc, point4, false); } template <typename Range> inline void add_range_to_piece(piece& pc, Range const& range, bool add_front) { BOOST_GEOMETRY_ASSERT(boost::size(range) != 0u); typename Range::const_iterator it = boost::begin(range); // If it follows a non-join (so basically the same piece-type) point b1 should be added. // There should be two intersections later and it should be discarded. // But for now we need it to calculate intersections if (add_front) { add_point(*it); } for (++it; it != boost::end(range); ++it) { pc.beyond_last_segment_index = add_point(*it); } } inline void add_piece(strategy::buffer::piece_type type, point_type const& p, point_type const& b1, point_type const& b2) { piece& pc = create_piece(type, false); add_point(b1); pc.beyond_last_segment_index = add_point(b2); finish_piece(pc, b2, p, b1); } template <typename Range> inline void add_piece(strategy::buffer::piece_type type, Range const& range, bool decrease_segment_index_by_one) { piece& pc = create_piece(type, decrease_segment_index_by_one); if (boost::size(range) > 0u) { add_range_to_piece(pc, range, offsetted_rings.back().empty()); } finish_piece(pc); } template <typename Range> inline void add_piece(strategy::buffer::piece_type type, point_type const& p, Range const& range) { piece& pc = create_piece(type, true); if (boost::size(range) > 0u) { add_range_to_piece(pc, range, offsetted_rings.back().empty()); finish_piece(pc, range.back(), p, range.front()); } else { finish_piece(pc); } } template <typename Range> inline void add_side_piece(point_type const& original_point1, point_type const& original_point2, Range const& range, bool first) { BOOST_GEOMETRY_ASSERT(boost::size(range) >= 2u); piece& pc = create_piece(strategy::buffer::buffered_segment, ! first); add_range_to_piece(pc, range, first); // Add the four points of the side, starting with the last point of the // range, and reversing the order of the originals to keep it clockwise finish_piece(pc, range.back(), original_point2, original_point1, range.front()); } template <typename EndcapStrategy, typename Range> inline void add_endcap(EndcapStrategy const& strategy, Range const& range, point_type const& end_point) { boost::ignore_unused(strategy); if (range.empty()) { return; } strategy::buffer::piece_type pt = strategy.get_piece_type(); if (pt == strategy::buffer::buffered_flat_end) { // It is flat, should just be added, without helper segments add_piece(pt, range, true); } else { // Normal case, it has an "inside", helper segments should be added add_piece(pt, end_point, range); } } inline void mark_flat_start(point_type const& point) { if (! m_pieces.empty()) { piece& back = m_pieces.back(); back.is_flat_start = true; // This happens to linear buffers, and it will be the very // first or last point. If that coincides with a turn, // and the turn was marked as ON_BORDER // the turn should NOT be within (even though it can be marked // as such) m_linear_end_points.push_back(point); } } inline void mark_flat_end(point_type const& point) { if (! m_pieces.empty()) { piece& back = m_pieces.back(); back.is_flat_end = true; m_linear_end_points.push_back(point); } } //------------------------------------------------------------------------- inline void enrich() { enrich_intersection_points<false, false, overlay_buffer>(m_turns, m_clusters, offsetted_rings, offsetted_rings, m_robust_policy, m_intersection_strategy); } // Discards all rings which do have not-OK intersection points only. // Those can never be traversed and should not be part of the output. inline void discard_rings() { for (typename boost::range_iterator<turn_vector_type const>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { if (it->is_turn_traversable) { offsetted_rings[it->operations[0].seg_id.multi_index].has_accepted_intersections = true; offsetted_rings[it->operations[1].seg_id.multi_index].has_accepted_intersections = true; } else { offsetted_rings[it->operations[0].seg_id.multi_index].has_discarded_intersections = true; offsetted_rings[it->operations[1].seg_id.multi_index].has_discarded_intersections = true; } } } inline bool point_coveredby_original(point_type const& point) { typedef typename IntersectionStrategy::disjoint_point_box_strategy_type d_pb_strategy_type; signed_size_type count_in_original = 0; // Check of the robust point of this outputted ring is in // any of the robust original rings // This can go quadratic if the input has many rings, and there // are many untouched deflated rings around for (typename std::vector<original_ring>::const_iterator it = original_rings.begin(); it != original_rings.end(); ++it) { original_ring const& original = *it; if (original.m_ring.empty()) { continue; } if (detail::disjoint::disjoint_point_box(point, original.m_box, d_pb_strategy_type())) { continue; } int const geometry_code = detail::within::point_in_geometry(point, original.m_ring, m_point_in_geometry_strategy); if (geometry_code == -1) { // Outside, continue continue; } // Apply for possibly nested interior rings if (original.m_is_interior) { count_in_original--; } else if (original.m_has_interiors) { count_in_original++; } else { // Exterior ring without interior rings return true; } } return count_in_original > 0; } // For a deflate, all rings around inner rings which are untouched // (no intersections/turns) and which are OUTSIDE the original should // be discarded inline void discard_nonintersecting_deflated_rings() { for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings); it != boost::end(offsetted_rings); ++it) { buffered_ring<Ring>& ring = *it; if (! ring.has_intersections() && boost::size(ring) > 0u && geometry::area(ring, m_area_strategy) < 0) { if (! point_coveredby_original(geometry::range::front(ring))) { ring.is_untouched_outside_original = true; } } } } inline void block_turns() { for (typename boost::range_iterator<turn_vector_type>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { buffer_turn_info_type& turn = *it; if (! turn.is_turn_traversable) { // Discard this turn (don't set it to blocked to avoid colocated // clusters being discarded afterwards turn.discarded = true; } } } inline void traverse() { typedef detail::overlay::traverse < false, false, buffered_ring_collection<buffered_ring<Ring> >, buffered_ring_collection<buffered_ring<Ring > >, overlay_buffer, backtrack_for_buffer > traverser; std::map<ring_identifier, overlay::ring_turn_info> turn_info_per_ring; traversed_rings.clear(); buffer_overlay_visitor visitor; traverser::apply(offsetted_rings, offsetted_rings, m_intersection_strategy, m_robust_policy, m_turns, traversed_rings, turn_info_per_ring, m_clusters, visitor); } inline void reverse() { for(typename buffered_ring_collection<buffered_ring<Ring> >::iterator it = boost::begin(offsetted_rings); it != boost::end(offsetted_rings); ++it) { if (! it->has_intersections()) { std::reverse(it->begin(), it->end()); } } for (typename boost::range_iterator<buffered_ring_collection<Ring> >::type it = boost::begin(traversed_rings); it != boost::end(traversed_rings); ++it) { std::reverse(it->begin(), it->end()); } } template <typename GeometryOutput, typename OutputIterator> inline OutputIterator assign(OutputIterator out) const { typedef detail::overlay::ring_properties<point_type, area_result_type> properties; std::map<ring_identifier, properties> selected; // Select all rings which do not have any self-intersection // Inner rings, for deflate, which do not have intersections, and // which are outside originals, are skipped // (other ones should be traversed) signed_size_type index = 0; for(typename buffered_ring_collection<buffered_ring<Ring> >::const_iterator it = boost::begin(offsetted_rings); it != boost::end(offsetted_rings); ++it, ++index) { if (! it->has_intersections() && ! it->is_untouched_outside_original) { properties p = properties(*it, m_area_strategy); if (p.valid) { ring_identifier id(0, index, -1); selected[id] = p; } } } // Select all created rings index = 0; for (typename boost::range_iterator<buffered_ring_collection<Ring> const>::type it = boost::begin(traversed_rings); it != boost::end(traversed_rings); ++it, ++index) { properties p = properties(*it, m_area_strategy); if (p.valid) { ring_identifier id(2, index, -1); selected[id] = p; } } detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings, selected, m_intersection_strategy); return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out, m_area_strategy); } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_PIECE_COLLECTION_HPP detail/buffer/get_piece_turns.hpp 0000644 00000027721 15125631657 0013173 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/sections/section_functions.hpp> #include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { // Implements a unique_sub_range for a buffered piece, // the range can return subsequent points // known as "i", "j" and "k" (and further), indexed as 0,1,2,3 template <typename Ring> struct unique_sub_range_from_piece { typedef typename boost::range_iterator<Ring const>::type iterator_type; typedef typename geometry::point_type<Ring const>::type point_type; unique_sub_range_from_piece(Ring const& ring, iterator_type iterator_at_i, iterator_type iterator_at_j) : m_ring(ring) , m_iterator_at_i(iterator_at_i) , m_iterator_at_j(iterator_at_j) , m_point_retrieved(false) {} static inline bool is_first_segment() { return false; } static inline bool is_last_segment() { return false; } static inline std::size_t size() { return 3u; } inline point_type const& at(std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < size()); switch (index) { case 0 : return *m_iterator_at_i; case 1 : return *m_iterator_at_j; case 2 : return get_point_k(); default : return *m_iterator_at_i; } } private : inline point_type const& get_point_k() const { if (! m_point_retrieved) { m_iterator_at_k = advance_one(m_iterator_at_j); m_point_retrieved = true; } return *m_iterator_at_k; } inline void circular_advance_one(iterator_type& next) const { ++next; if (next == boost::end(m_ring)) { next = boost::begin(m_ring) + 1; } } inline iterator_type advance_one(iterator_type it) const { iterator_type result = it; circular_advance_one(result); // TODO: we could also use piece-boundaries // to check if the point equals the last one while (geometry::equals(*it, *result)) { circular_advance_one(result); } return result; } Ring const& m_ring; iterator_type m_iterator_at_i; iterator_type m_iterator_at_j; mutable iterator_type m_iterator_at_k; mutable bool m_point_retrieved; }; template < typename Pieces, typename Rings, typename Turns, typename IntersectionStrategy, typename RobustPolicy > class piece_turn_visitor { Pieces const& m_pieces; Rings const& m_rings; Turns& m_turns; IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; template <typename Piece> inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const { if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index) { return false; } return piece1.index == piece2.left_index || piece1.index == piece2.right_index; } template <typename Piece> inline bool is_on_same_convex_ring(Piece const& piece1, Piece const& piece2) const { if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index) { return false; } return ! m_rings[piece1.first_seg_id.multi_index].has_concave; } template <std::size_t Dimension, typename Iterator, typename Box> inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond, signed_size_type& index, int dir, Box const& this_bounding_box, Box const& other_bounding_box) { for(; it_begin != it_beyond && it_begin + 1 != it_beyond && detail::section::preceding<Dimension>(dir, *(it_begin + 1), this_bounding_box, other_bounding_box, m_robust_policy); ++it_begin, index++) {} } template <std::size_t Dimension, typename Iterator, typename Box> inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond, int dir, Box const& this_bounding_box, Box const& other_bounding_box) { while (it_beyond != it_begin && it_beyond - 1 != it_begin && it_beyond - 2 != it_begin) { if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2), this_bounding_box, other_bounding_box, m_robust_policy)) { --it_beyond; } else { return; } } } template <typename Piece, typename Section> inline void calculate_turns(Piece const& piece1, Piece const& piece2, Section const& section1, Section const& section2) { typedef typename boost::range_value<Rings const>::type ring_type; typedef typename boost::range_value<Turns const>::type turn_type; typedef typename boost::range_iterator<ring_type const>::type iterator; signed_size_type const piece1_first_index = piece1.first_seg_id.segment_index; signed_size_type const piece2_first_index = piece2.first_seg_id.segment_index; if (piece1_first_index < 0 || piece2_first_index < 0) { return; } // Get indices of part of offsetted_rings for this monotonic section: signed_size_type const sec1_first_index = piece1_first_index + section1.begin_index; signed_size_type const sec2_first_index = piece2_first_index + section2.begin_index; // index of last point in section, beyond-end is one further signed_size_type const sec1_last_index = piece1_first_index + section1.end_index; signed_size_type const sec2_last_index = piece2_first_index + section2.end_index; // get geometry and iterators over these sections ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index]; iterator it1_first = boost::begin(ring1) + sec1_first_index; iterator it1_beyond = boost::begin(ring1) + sec1_last_index + 1; ring_type const& ring2 = m_rings[piece2.first_seg_id.multi_index]; iterator it2_first = boost::begin(ring2) + sec2_first_index; iterator it2_beyond = boost::begin(ring2) + sec2_last_index + 1; // Set begin/end of monotonic ranges, in both x/y directions signed_size_type index1 = sec1_first_index; move_begin_iterator<0>(it1_first, it1_beyond, index1, section1.directions[0], section1.bounding_box, section2.bounding_box); move_end_iterator<0>(it1_first, it1_beyond, section1.directions[0], section1.bounding_box, section2.bounding_box); move_begin_iterator<1>(it1_first, it1_beyond, index1, section1.directions[1], section1.bounding_box, section2.bounding_box); move_end_iterator<1>(it1_first, it1_beyond, section1.directions[1], section1.bounding_box, section2.bounding_box); signed_size_type index2 = sec2_first_index; move_begin_iterator<0>(it2_first, it2_beyond, index2, section2.directions[0], section2.bounding_box, section1.bounding_box); move_end_iterator<0>(it2_first, it2_beyond, section2.directions[0], section2.bounding_box, section1.bounding_box); move_begin_iterator<1>(it2_first, it2_beyond, index2, section2.directions[1], section2.bounding_box, section1.bounding_box); move_end_iterator<1>(it2_first, it2_beyond, section2.directions[1], section2.bounding_box, section1.bounding_box); turn_type the_model; the_model.operations[0].piece_index = piece1.index; the_model.operations[0].seg_id = piece1.first_seg_id; the_model.operations[0].seg_id.segment_index = index1; // override iterator it1 = it1_first; for (iterator prev1 = it1++; it1 != it1_beyond; prev1 = it1++, the_model.operations[0].seg_id.segment_index++) { the_model.operations[1].piece_index = piece2.index; the_model.operations[1].seg_id = piece2.first_seg_id; the_model.operations[1].seg_id.segment_index = index2; // override unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1); iterator it2 = it2_first; for (iterator prev2 = it2++; it2 != it2_beyond; prev2 = it2++, the_model.operations[1].seg_id.segment_index++) { unique_sub_range_from_piece<ring_type> unique_sub_range2(ring2, prev2, it2); typedef detail::overlay::get_turn_info < detail::overlay::assign_policy_only_start_turns > turn_policy; turn_policy::apply(unique_sub_range1, unique_sub_range2, the_model, m_intersection_strategy, m_robust_policy, std::back_inserter(m_turns)); } } } public: piece_turn_visitor(Pieces const& pieces, Rings const& ring_collection, Turns& turns, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) : m_pieces(pieces) , m_rings(ring_collection) , m_turns(turns) , m_intersection_strategy(intersection_strategy) , m_robust_policy(robust_policy) {} template <typename Section> inline bool apply(Section const& section1, Section const& section2, bool first = true) { boost::ignore_unused(first); typedef typename boost::range_value<Pieces const>::type piece_type; piece_type const& piece1 = m_pieces[section1.ring_id.source_index]; piece_type const& piece2 = m_pieces[section2.ring_id.source_index]; if ( piece1.index == piece2.index || is_adjacent(piece1, piece2) || is_on_same_convex_ring(piece1, piece2) || detail::disjoint::disjoint_box_box(section1.bounding_box, section2.bounding_box, m_intersection_strategy.get_disjoint_box_box_strategy()) ) { return true; } calculate_turns(piece1, piece2, section1, section2); return true; } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP detail/buffer/line_line_intersection.hpp 0000644 00000003152 15125631657 0014530 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP #include <boost/geometry/core/assert.hpp> #include <boost/geometry/arithmetic/infinite_line_functions.hpp> #include <boost/geometry/algorithms/detail/make/make.hpp> #include <boost/core/ignore_unused.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace buffer { // TODO: this might once be changed to a proper strategy struct line_line_intersection { template <typename Point> static inline bool apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj, Point& ip) { typedef typename coordinate_type<Point>::type ct; typedef model::infinite_line<ct> line_type; line_type const p = detail::make::make_infinite_line<ct>(pi, pj); line_type const q = detail::make::make_infinite_line<ct>(qi, qj); // The input lines are not parallel, they intersect, because // their join type is checked before. return arithmetic::intersection_point(p, q, ip); } }; }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP detail/calculate_sum.hpp 0000644 00000004165 15125631657 0011361 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // This file was modified by Oracle on 2016-2020. // Modifications copyright (c) 2016-2020 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { class calculate_polygon_sum { template <typename ReturnType, typename Policy, typename Rings, typename Strategy> static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy) { ReturnType sum = ReturnType(0); for (typename boost::range_iterator<Rings const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { sum += Policy::apply(*it, strategy); } return sum; } public : template <typename ReturnType, typename Policy, typename Polygon, typename Strategy> static inline ReturnType apply(Polygon const& poly, Strategy const& strategy) { return Policy::apply(exterior_ring(poly), strategy) + sum_interior_rings<ReturnType, Policy>(interior_rings(poly), strategy) ; } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP detail/comparable_distance/implementation.hpp 0000644 00000002074 15125631657 0015541 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/distance/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP detail/comparable_distance/interface.hpp 0000644 00000026234 15125631657 0014460 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014, 2019. // Modifications copyright (c) 2014, 2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/comparable_distance_result.hpp> #include <boost/geometry/strategies/default_comparable_distance_result.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/algorithms/detail/distance/interface.hpp> namespace boost { namespace geometry { namespace resolve_strategy { template <typename Strategy> struct comparable_distance { template <typename Geometry1, typename Geometry2> static inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename strategy::distance::services::comparable_type < Strategy >::type comparable_strategy_type; return dispatch::distance < Geometry1, Geometry2, comparable_strategy_type >::apply(geometry1, geometry2, strategy::distance::services::get_comparable < Strategy >::apply(strategy)); } }; template <> struct comparable_distance<default_strategy> { template <typename Geometry1, typename Geometry2> static inline typename comparable_distance_result < Geometry1, Geometry2, default_strategy >::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::distance::services::comparable_type < typename detail::distance::default_strategy < Geometry1, Geometry2 >::type >::type comparable_strategy_type; return dispatch::distance < Geometry1, Geometry2, comparable_strategy_type >::apply(geometry1, geometry2, comparable_strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct comparable_distance { template <typename Strategy> static inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_strategy::comparable_distance < Strategy >::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct comparable_distance < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2 > { template <typename Strategy> struct visitor: static_visitor < typename comparable_distance_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2, Strategy >::type > { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2), m_strategy(strategy) {} template <typename Geometry1> typename comparable_distance_result < Geometry1, Geometry2, Strategy >::type operator()(Geometry1 const& geometry1) const { return comparable_distance < Geometry1, Geometry2 >::template apply < Strategy >(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline typename comparable_distance_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2, Strategy >::type apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct comparable_distance < Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: static_visitor < typename comparable_distance_result < Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy >::type > { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1), m_strategy(strategy) {} template <typename Geometry2> typename comparable_distance_result < Geometry1, Geometry2, Strategy >::type operator()(Geometry2 const& geometry2) const { return comparable_distance < Geometry1, Geometry2 >::template apply < Strategy >(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline typename comparable_distance_result < Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Strategy >::type apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct comparable_distance < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: static_visitor < typename comparable_distance_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type > { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> typename comparable_distance_result < Geometry1, Geometry2, Strategy >::type operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return comparable_distance < Geometry1, Geometry2 >::template apply < Strategy >(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline typename comparable_distance_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>, Strategy >::type apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_calc2{comparable distance measurement} \brief_strategy \ingroup distance \details The free function comparable_distance does not necessarily calculate the distance, but it calculates a distance measure such that two distances are comparable to each other. For example: for the Cartesian coordinate system, Pythagoras is used but the square root is not taken, which makes it faster and the results of two point pairs can still be compared to each other. \tparam Geometry1 first geometry type \tparam Geometry2 second geometry type \tparam Strategy \tparam_strategy{Distance} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{distance} \return \return_calc{comparable distance} \qbk{distinguish,with strategy} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return resolve_variant::comparable_distance < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief \brief_calc2{comparable distance measurement} \ingroup distance \details The free function comparable_distance does not necessarily calculate the distance, but it calculates a distance measure such that two distances are comparable to each other. For example: for the Cartesian coordinate system, Pythagoras is used but the square root is not taken, which makes it faster and the results of two point pairs can still be compared to each other. \tparam Geometry1 first geometry type \tparam Geometry2 second geometry type \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_calc{comparable distance} \qbk{[include reference/algorithms/comparable_distance.qbk]} */ template <typename Geometry1, typename Geometry2> inline typename default_comparable_distance_result<Geometry1, Geometry2>::type comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return geometry::comparable_distance(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP detail/throw_on_empty_input.hpp 0000644 00000004031 15125631657 0013024 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2015. // Modifications copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP #include <boost/geometry/core/exception.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/throw_exception.hpp> // BSG 2012-02-06: we use this currently only for distance. // For other scalar results area,length,perimeter it is commented on purpose. // Reason is that for distance there is no other choice. distance of two // empty geometries (or one empty) should NOT return any value. // But for area it is no problem to be 0. // Suppose: area(intersection(a,b)). We (probably) don't want a throw there... // So decided that at least for Boost 1.49 this is commented for // scalar results, except distance. #if defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW) #include <boost/core/ignore_unused.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename Geometry> inline void throw_on_empty_input(Geometry const& geometry) { #if ! defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW) if (geometry::is_empty(geometry)) { BOOST_THROW_EXCEPTION(empty_input_exception()); } #else boost::ignore_unused(geometry); #endif } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP detail/single_geometry.hpp 0000644 00000005302 15125631657 0011726 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP #include <type_traits> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { // Returns single geometry by Id // for single geometries returns the geometry itself template < typename Geometry, bool IsMulti = std::is_base_of < multi_tag, typename geometry::tag<Geometry>::type >::value > struct single_geometry { typedef Geometry & return_type; template <typename Id> static inline return_type apply(Geometry & g, Id const& ) { return g; } }; // for multi geometries returns one of the stored single geometries template <typename Geometry> struct single_geometry<Geometry, true> { typedef typename boost::range_reference<Geometry>::type return_type; template <typename Id> static inline return_type apply(Geometry & g, Id const& id) { BOOST_GEOMETRY_ASSERT(id.multi_index >= 0); typedef typename boost::range_size<Geometry>::type size_type; return range::at(g, static_cast<size_type>(id.multi_index)); } }; } // namespace detail_dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename Geometry> struct single_geometry_return_type { typedef typename detail_dispatch::single_geometry<Geometry>::return_type type; }; template <typename Geometry, typename Id> inline typename single_geometry_return_type<Geometry>::type single_geometry(Geometry & geometry, Id const& id) { return detail_dispatch::single_geometry<Geometry>::apply(geometry, id); } template <typename Geometry, typename Id> inline typename single_geometry_return_type<Geometry const>::type single_geometry(Geometry const& geometry, Id const& id) { return detail_dispatch::single_geometry<Geometry const>::apply(geometry, id); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SINGLE_GEOMETRY_HPP detail/normalize.hpp 0000644 00000002420 15125631657 0010530 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_NORMALIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NORMALIZE_HPP // For backward compatibility #include <boost/geometry/strategies/normalize.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename GeometryIn, typename GeometryOut, typename Strategy> inline void normalize(GeometryIn const& geometry_in, GeometryOut& geometry_out, Strategy const& ) { Strategy::apply(geometry_in, geometry_out); } template <typename GeometryOut, typename GeometryIn, typename Strategy> inline GeometryOut return_normalized(GeometryIn const& geometry_in, Strategy const& strategy) { GeometryOut geometry_out; detail::normalize(geometry_in, geometry_out, strategy); return geometry_out; } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NORMALIZE_HPP detail/covered_by/implementation.hpp 0000644 00000021733 15125631657 0013706 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013, 2014, 2017, 2019. // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP #include <cstddef> #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/detail/covered_by/interface.hpp> #include <boost/geometry/algorithms/detail/within/implementation.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace covered_by { struct use_point_in_geometry { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return detail::within::covered_by_point_geometry(geometry1, geometry2, strategy); } }; struct use_relate { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename detail::de9im::static_mask_covered_by_type < Geometry1, Geometry2 >::type covered_by_mask; return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy); } }; }} // namespace detail::covered_by #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point, typename Box> struct covered_by<Point, Box, point_tag, box_tag> { template <typename Strategy> static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) { ::boost::ignore_unused(strategy); return strategy.apply(point, box); } }; template <typename Box1, typename Box2> struct covered_by<Box1, Box2, box_tag, box_tag> { template <typename Strategy> static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy) { assert_dimension_equal<Box1, Box2>(); ::boost::ignore_unused(strategy); return strategy.apply(box1, box2); } }; // P/P template <typename Point1, typename Point2> struct covered_by<Point1, Point2, point_tag, point_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename Point, typename MultiPoint> struct covered_by<Point, MultiPoint, point_tag, multi_point_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename MultiPoint, typename Point> struct covered_by<MultiPoint, Point, multi_point_tag, point_tag> : public detail::within::multi_point_point {}; template <typename MultiPoint1, typename MultiPoint2> struct covered_by<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag> : public detail::within::multi_point_multi_point {}; // P/L template <typename Point, typename Segment> struct covered_by<Point, Segment, point_tag, segment_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename Point, typename Linestring> struct covered_by<Point, Linestring, point_tag, linestring_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename Point, typename MultiLinestring> struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename MultiPoint, typename Segment> struct covered_by<MultiPoint, Segment, multi_point_tag, segment_tag> : public detail::within::multi_point_single_geometry<false> {}; template <typename MultiPoint, typename Linestring> struct covered_by<MultiPoint, Linestring, multi_point_tag, linestring_tag> : public detail::within::multi_point_single_geometry<false> {}; template <typename MultiPoint, typename MultiLinestring> struct covered_by<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag> : public detail::within::multi_point_multi_geometry<false> {}; // P/A template <typename Point, typename Ring> struct covered_by<Point, Ring, point_tag, ring_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename Point, typename Polygon> struct covered_by<Point, Polygon, point_tag, polygon_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename Point, typename MultiPolygon> struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag> : public detail::covered_by::use_point_in_geometry {}; template <typename MultiPoint, typename Ring> struct covered_by<MultiPoint, Ring, multi_point_tag, ring_tag> : public detail::within::multi_point_single_geometry<false> {}; template <typename MultiPoint, typename Polygon> struct covered_by<MultiPoint, Polygon, multi_point_tag, polygon_tag> : public detail::within::multi_point_single_geometry<false> {}; template <typename MultiPoint, typename MultiPolygon> struct covered_by<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag> : public detail::within::multi_point_multi_geometry<false> {}; // L/L template <typename Linestring1, typename Linestring2> struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag> : public detail::covered_by::use_relate {}; template <typename Linestring, typename MultiLinestring> struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag> : public detail::covered_by::use_relate {}; template <typename MultiLinestring, typename Linestring> struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag> : public detail::covered_by::use_relate {}; template <typename MultiLinestring1, typename MultiLinestring2> struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag> : public detail::covered_by::use_relate {}; // L/A template <typename Linestring, typename Ring> struct covered_by<Linestring, Ring, linestring_tag, ring_tag> : public detail::covered_by::use_relate {}; template <typename MultiLinestring, typename Ring> struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag> : public detail::covered_by::use_relate {}; template <typename Linestring, typename Polygon> struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag> : public detail::covered_by::use_relate {}; template <typename MultiLinestring, typename Polygon> struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag> : public detail::covered_by::use_relate {}; template <typename Linestring, typename MultiPolygon> struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag> : public detail::covered_by::use_relate {}; template <typename MultiLinestring, typename MultiPolygon> struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag> : public detail::covered_by::use_relate {}; // A/A template <typename Ring1, typename Ring2> struct covered_by<Ring1, Ring2, ring_tag, ring_tag> : public detail::covered_by::use_relate {}; template <typename Ring, typename Polygon> struct covered_by<Ring, Polygon, ring_tag, polygon_tag> : public detail::covered_by::use_relate {}; template <typename Polygon, typename Ring> struct covered_by<Polygon, Ring, polygon_tag, ring_tag> : public detail::covered_by::use_relate {}; template <typename Polygon1, typename Polygon2> struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag> : public detail::covered_by::use_relate {}; template <typename Ring, typename MultiPolygon> struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag> : public detail::covered_by::use_relate {}; template <typename MultiPolygon, typename Ring> struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag> : public detail::covered_by::use_relate {}; template <typename Polygon, typename MultiPolygon> struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag> : public detail::covered_by::use_relate {}; template <typename MultiPolygon, typename Polygon> struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag> : public detail::covered_by::use_relate {}; template <typename MultiPolygon1, typename MultiPolygon2> struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag> : public detail::covered_by::use_relate {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP detail/covered_by/interface.hpp 0000644 00000020372 15125631657 0012617 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013, 2014, 2017, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/within/interface.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/strategies/cartesian/point_in_box.hpp> #include <boost/geometry/strategies/cartesian/box_in_box.hpp> #include <boost/geometry/strategies/default_strategy.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > struct covered_by : not_implemented<Tag1, Tag2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct covered_by { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::within::check<Geometry1, Geometry2, Strategy>(); concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); assert_dimension_equal<Geometry1, Geometry2>(); return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::covered_by::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return covered_by::apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct covered_by { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_strategy::covered_by ::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2), m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return covered_by<Geometry1, Geometry2> ::apply(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1), m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return covered_by<Geometry1, Geometry2> ::apply(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct covered_by< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy): m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return covered_by<Geometry1, Geometry2> ::apply(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_check12{is inside or on border} \ingroup covered_by \details \details_check12{covered_by, is inside or on border}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry which might be inside or on the border of the second geometry \param geometry2 \param_geometry which might cover the first geometry \return true if geometry1 is inside of or on the border of geometry2, else false \note The default strategy is used for covered_by detection \qbk{[include reference/algorithms/covered_by.qbk]} \qbk{ [heading Examples] [covered_by] [covered_by_output] } */ template<typename Geometry1, typename Geometry2> inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::covered_by<Geometry1, Geometry2> ::apply(geometry1, geometry2, default_strategy()); } /*! \brief \brief_check12{is inside or on border} \brief_strategy \ingroup covered_by \details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry which might be inside or on the border of the second geometry \param geometry2 \param_geometry which might cover the first geometry \param strategy strategy to be used \return true if geometry1 is inside of or on the border of geometry2, else false \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/covered_by.qbk]} */ template<typename Geometry1, typename Geometry2, typename Strategy> inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::covered_by<Geometry1, Geometry2> ::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP detail/intersects/implementation.hpp 0000644 00000005232 15125631657 0013744 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013-2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP #include <deque> #include <boost/geometry/algorithms/detail/intersects/interface.hpp> #include <boost/geometry/algorithms/detail/disjoint/implementation.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/policies/disjoint_interrupt_policy.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> #include <boost/geometry/strategies/relate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersects { template <typename Geometry> struct self_intersects { static bool apply(Geometry const& geometry) { concepts::check<Geometry const>(); typedef typename geometry::point_type<Geometry>::type point_type; typedef typename strategy::relate::services::default_strategy < Geometry, Geometry >::type strategy_type; typedef detail::overlay::turn_info<point_type> turn_info; std::deque<turn_info> turns; typedef detail::overlay::get_turn_info < detail::overlay::assign_null_policy > turn_policy; strategy_type strategy; detail::disjoint::disjoint_interrupt_policy policy; // TODO: skip_adjacent should be set to false detail::self_get_turn_points::get_turns < false, turn_policy >::apply(geometry, strategy, detail::no_rescale_policy(), turns, policy, 0, true); return policy.has_intersections; } }; }} // namespace detail::intersects #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP detail/intersects/interface.hpp 0000644 00000006651 15125631657 0012665 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013-2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/disjoint/interface.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersects { // Forward declaration template <typename Geometry> struct self_intersects; }} // namespace detail::intersects #endif // DOXYGEN_NO_DETAIL /*! \brief \brief_check{has at least one intersection (crossing or self-tangency)} \note This function can be called for one geometry (self-intersection) and also for two geometries (intersection) \ingroup intersects \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_check{is self-intersecting} \qbk{distinguish,one geometry} \qbk{[def __one_parameter__]} \qbk{[include reference/algorithms/intersects.qbk]} */ template <typename Geometry> inline bool intersects(Geometry const& geometry) { return detail::intersects::self_intersects<Geometry>::apply(geometry); } /*! \brief \brief_check2{have at least one intersection} \ingroup intersects \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Intersects} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{intersects} \return \return_check2{intersect each other} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/intersects.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return ! geometry::disjoint(geometry1, geometry2, strategy); } /*! \brief \brief_check2{have at least one intersection} \ingroup intersects \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{intersect each other} \qbk{distinguish,two geometries} \qbk{[include reference/algorithms/intersects.qbk]} */ template <typename Geometry1, typename Geometry2> inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return ! geometry::disjoint(geometry1, geometry2); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP detail/has_self_intersections.hpp 0000644 00000012460 15125631657 0013272 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP #include <deque> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/throw_exception.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/policies/disjoint_interrupt_policy.hpp> #include <boost/geometry/policies/robustness/robust_point_type.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> # include <boost/geometry/io/dsv/write.hpp> #endif namespace boost { namespace geometry { #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) /*! \brief Overlay Invalid Input Exception \ingroup overlay \details The overlay_invalid_input_exception is thrown at invalid input */ class overlay_invalid_input_exception : public geometry::exception { public: inline overlay_invalid_input_exception() {} virtual char const* what() const throw() { return "Boost.Geometry Overlay invalid input exception"; } }; #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Geometry, typename Strategy, typename RobustPolicy> inline bool has_self_intersections(Geometry const& geometry, Strategy const& strategy, RobustPolicy const& robust_policy, bool throw_on_self_intersection = true) { typedef typename point_type<Geometry>::type point_type; typedef turn_info < point_type, typename segment_ratio_type<point_type, RobustPolicy>::type > turn_info; std::deque<turn_info> turns; detail::disjoint::disjoint_interrupt_policy policy; detail::self_get_turn_points::self_turns < false, detail::overlay::assign_null_policy >(geometry, strategy, robust_policy, turns, policy, 0, false); #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS bool first = true; #endif for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns); it != boost::end(turns); ++it) { turn_info const& info = *it; bool const both_union_turn = info.operations[0].operation == detail::overlay::operation_union && info.operations[1].operation == detail::overlay::operation_union; bool const both_intersection_turn = info.operations[0].operation == detail::overlay::operation_intersection && info.operations[1].operation == detail::overlay::operation_intersection; bool const valid = (both_union_turn || both_intersection_turn) && (info.method == detail::overlay::method_touch || info.method == detail::overlay::method_touch_interior); if (! valid) { #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS if (first) { std::cout << "turn points: " << std::endl; first = false; } std::cout << method_char(info.method); for (int i = 0; i < 2; i++) { std::cout << " " << operation_char(info.operations[i].operation); std::cout << " " << info.operations[i].seg_id; } std::cout << " " << geometry::dsv(info.point) << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) if (throw_on_self_intersection) { BOOST_THROW_EXCEPTION(overlay_invalid_input_exception()); } #endif return true; } } return false; } // For backward compatibility template <typename Geometry> inline bool has_self_intersections(Geometry const& geometry, bool throw_on_self_intersection = true) { typedef typename geometry::point_type<Geometry>::type point_type; typedef typename geometry::rescale_policy_type<point_type>::type rescale_policy_type; typename strategy::intersection::services::default_strategy < typename cs_tag<Geometry>::type >::type strategy; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>(geometry, strategy); return has_self_intersections(geometry, strategy, robust_policy, throw_on_self_intersection); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP detail/calculate_point_order.hpp 0000644 00000026607 15125631657 0013106 0 ustar 00 // Boost.Geometry // Copyright (c) 2019-2020, 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_DETAIL_CALCULATE_POINT_ORDER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP #include <vector> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/radian_access.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/strategies/geographic/point_order.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { namespace detail { template <typename Iter, typename CalcT> struct clean_point { explicit clean_point(Iter const& iter) : m_iter(iter), m_azi(0), m_razi(0), m_azi_diff(0) , m_is_azi_valid(false), m_is_azi_diff_valid(false) {} typename boost::iterators::iterator_reference<Iter>::type ref() const { return *m_iter; } CalcT const& azimuth() const { return m_azi; } CalcT const& reverse_azimuth() const { return m_razi; } CalcT const& azimuth_difference() const { return m_azi_diff; } void set_azimuths(CalcT const& azi, CalcT const& razi) { m_azi = azi; m_razi = razi; m_is_azi_valid = true; } void set_azimuth_invalid() { m_is_azi_valid = false; } bool is_azimuth_valid() const { return m_is_azi_valid; } void set_azimuth_difference(CalcT const& diff) { m_azi_diff = diff; m_is_azi_diff_valid = true; } void set_azimuth_difference_invalid() { m_is_azi_diff_valid = false; } bool is_azimuth_difference_valid() const { return m_is_azi_diff_valid; } private: Iter m_iter; CalcT m_azi; CalcT m_razi; CalcT m_azi_diff; // NOTE: these flags could be removed and replaced with some magic number // assigned to the above variables, e.g. CalcT(1000). bool m_is_azi_valid; bool m_is_azi_diff_valid; }; struct calculate_point_order_by_azimuth { template <typename Ring, typename Strategy> static geometry::order_selector apply(Ring const& ring, Strategy const& strategy) { typedef typename boost::range_iterator<Ring const>::type iter_t; typedef typename Strategy::template result_type<Ring>::type calc_t; typedef clean_point<iter_t, calc_t> clean_point_t; typedef std::vector<clean_point_t> cleaned_container_t; typedef typename cleaned_container_t::iterator cleaned_iter_t; calc_t const zero = 0; calc_t const pi = math::pi<calc_t>(); std::size_t const count = boost::size(ring); if (count < 3) { return geometry::order_undetermined; } // non-duplicated, non-spike points cleaned_container_t cleaned; cleaned.reserve(count); for (iter_t it = boost::begin(ring); it != boost::end(ring); ++it) { // Add point cleaned.push_back(clean_point_t(it)); while (cleaned.size() >= 3) { cleaned_iter_t it0 = cleaned.end() - 3; cleaned_iter_t it1 = cleaned.end() - 2; cleaned_iter_t it2 = cleaned.end() - 1; calc_t diff; if (get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy) && ! math::equals(math::abs(diff), pi)) { // neither duplicate nor a spike - difference already stored break; } else { // spike detected // TODO: angles have to be invalidated only if spike is detected // for duplicates it'd be ok to leave them it0->set_azimuth_invalid(); it0->set_azimuth_difference_invalid(); it2->set_azimuth_difference_invalid(); cleaned.erase(it1); } } } // filter-out duplicates and spikes at the front and back of cleaned cleaned_iter_t cleaned_b = cleaned.begin(); cleaned_iter_t cleaned_e = cleaned.end(); std::size_t cleaned_count = cleaned.size(); bool found = false; do { found = false; while(cleaned_count >= 3) { cleaned_iter_t it0 = cleaned_e - 2; cleaned_iter_t it1 = cleaned_e - 1; cleaned_iter_t it2 = cleaned_b; cleaned_iter_t it3 = cleaned_b + 1; calc_t diff = 0; if (! get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy) || math::equals(math::abs(diff), pi)) { // spike at the back // TODO: angles have to be invalidated only if spike is detected // for duplicates it'd be ok to leave them it0->set_azimuth_invalid(); it0->set_azimuth_difference_invalid(); it2->set_azimuth_difference_invalid(); --cleaned_e; --cleaned_count; found = true; } else if (! get_or_calculate_azimuths_difference(*it1, *it2, *it3, diff, strategy) || math::equals(math::abs(diff), pi)) { // spike at the front // TODO: angles have to be invalidated only if spike is detected // for duplicates it'd be ok to leave them it1->set_azimuth_invalid(); it1->set_azimuth_difference_invalid(); it3->set_azimuth_difference_invalid(); ++cleaned_b; --cleaned_count; found = true; } else { break; } } } while (found); if (cleaned_count < 3) { return geometry::order_undetermined; } // calculate the sum of external angles calc_t angles_sum = zero; for (cleaned_iter_t it = cleaned_b; it != cleaned_e; ++it) { cleaned_iter_t it0 = (it == cleaned_b ? cleaned_e - 1 : it - 1); cleaned_iter_t it2 = (it == cleaned_e - 1 ? cleaned_b : it + 1); calc_t diff = 0; get_or_calculate_azimuths_difference(*it0, *it, *it2, diff, strategy); angles_sum += diff; } #ifdef BOOST_GEOMETRY_DEBUG_POINT_ORDER std::cout << angles_sum << " for " << geometry::wkt(ring) << std::endl; #endif return angles_sum == zero ? geometry::order_undetermined : angles_sum > zero ? geometry::clockwise : geometry::counterclockwise; } private: template <typename Iter, typename T, typename Strategy> static bool get_or_calculate_azimuths_difference(clean_point<Iter, T> & p0, clean_point<Iter, T> & p1, clean_point<Iter, T> const& p2, T & diff, Strategy const& strategy) { if (p1.is_azimuth_difference_valid()) { diff = p1.azimuth_difference(); return true; } T azi1, razi1, azi2, razi2; if (get_or_calculate_azimuths(p0, p1, azi1, razi1, strategy) && get_or_calculate_azimuths(p1, p2, azi2, razi2, strategy)) { diff = strategy.apply(p0.ref(), p1.ref(), p2.ref(), razi1, azi2); p1.set_azimuth_difference(diff); return true; } return false; } template <typename Iter, typename T, typename Strategy> static bool get_or_calculate_azimuths(clean_point<Iter, T> & p0, clean_point<Iter, T> const& p1, T & azi, T & razi, Strategy const& strategy) { if (p0.is_azimuth_valid()) { azi = p0.azimuth(); razi = p0.reverse_azimuth(); return true; } if (strategy.apply(p0.ref(), p1.ref(), azi, razi)) { p0.set_azimuths(azi, razi); return true; } return false; } }; struct calculate_point_order_by_area { template <typename Ring, typename Strategy> static geometry::order_selector apply(Ring const& ring, Strategy const& strategy) { typedef detail::area::ring_area < geometry::order_as_direction<geometry::point_order<Ring>::value>::value, geometry::closure<Ring>::value > ring_area_type; typedef typename area_result < Ring, Strategy >::type result_type; result_type const result = ring_area_type::apply(ring, // TEMP - in the future (umbrella) strategy will be passed geometry::strategies::area::services::strategy_converter < decltype(strategy.get_area_strategy()) >::get(strategy.get_area_strategy())); result_type const zero = 0; return result == zero ? geometry::order_undetermined : result > zero ? geometry::clockwise : geometry::counterclockwise; } }; } // namespace detail namespace dispatch { template < typename Strategy, typename VersionTag = typename Strategy::version_tag > struct calculate_point_order { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not implemented for this VersionTag.", VersionTag); }; template <typename Strategy> struct calculate_point_order<Strategy, strategy::point_order::area_tag> : geometry::detail::calculate_point_order_by_area {}; template <typename Strategy> struct calculate_point_order<Strategy, strategy::point_order::azimuth_tag> : geometry::detail::calculate_point_order_by_azimuth {}; } // namespace dispatch namespace detail { template <typename Ring, typename Strategy> inline geometry::order_selector calculate_point_order(Ring const& ring, Strategy const& strategy) { concepts::check<Ring>(); return dispatch::calculate_point_order<Strategy>::apply(ring, strategy); } template <typename Ring> inline geometry::order_selector calculate_point_order(Ring const& ring) { typedef typename strategy::point_order::services::default_strategy < typename geometry::cs_tag<Ring>::type >::type strategy_type; concepts::check<Ring>(); return dispatch::calculate_point_order<strategy_type>::apply(ring, strategy_type()); } } // namespace detail }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP detail/point_on_border.hpp 0000644 00000012262 15125631657 0011717 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.Dimension. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP #include <cstddef> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace point_on_border { struct get_point { template <typename Point> static inline bool apply(Point& destination, Point const& source) { destination = source; return true; } }; struct point_on_range { // Version with iterator template<typename Point, typename Iterator> static inline bool apply(Point& point, Iterator begin, Iterator end) { if (begin == end) { return false; } geometry::detail::conversion::convert_point_to_point(*begin, point); return true; } // Version with range template<typename Point, typename Range> static inline bool apply(Point& point, Range const& range) { return apply(point, boost::begin(range), boost::end(range)); } }; struct point_on_polygon { template<typename Point, typename Polygon> static inline bool apply(Point& point, Polygon const& polygon) { return point_on_range::apply(point, exterior_ring(polygon)); } }; struct point_on_box { template<typename Point, typename Box> static inline bool apply(Point& point, Box const& box) { detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point); return true; } }; template <typename Policy> struct point_on_multi { template<typename Point, typename MultiGeometry> static inline bool apply(Point& point, MultiGeometry const& multi) { // Take a point on the first multi-geometry // (i.e. the first that is not empty) for (typename boost::range_iterator < MultiGeometry const >::type it = boost::begin(multi); it != boost::end(multi); ++it) { if (Policy::apply(point, *it)) { return true; } } return false; } }; }} // namespace detail::point_on_border #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename GeometryTag> struct point_on_border {}; template <> struct point_on_border<point_tag> : detail::point_on_border::get_point {}; template <> struct point_on_border<linestring_tag> : detail::point_on_border::point_on_range {}; template <> struct point_on_border<ring_tag> : detail::point_on_border::point_on_range {}; template <> struct point_on_border<polygon_tag> : detail::point_on_border::point_on_polygon {}; template <> struct point_on_border<box_tag> : detail::point_on_border::point_on_box {}; template <> struct point_on_border<multi_polygon_tag> : detail::point_on_border::point_on_multi < detail::point_on_border::point_on_polygon > {}; template <> struct point_on_border<multi_linestring_tag> : detail::point_on_border::point_on_multi < detail::point_on_border::point_on_range > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief Take point on a border \ingroup overlay \tparam Geometry geometry type. This also defines the type of the output point \param point to assign \param geometry geometry to take point from \return TRUE if successful, else false. It is only false if polygon/line have no points \note for a polygon, it is always a point on the exterior ring */ template <typename Point, typename Geometry> inline bool point_on_border(Point& point, Geometry const& geometry) { concepts::check<Point>(); concepts::check<Geometry const>(); return dispatch::point_on_border < typename tag<Geometry>::type >::apply(point, geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP detail/disjoint/multirange_geometry.hpp 0000644 00000005544 15125631657 0014447 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { template <typename Geometry, typename Strategy, typename BinaryPredicate> class unary_disjoint_geometry_to_query_geometry { public: unary_disjoint_geometry_to_query_geometry(Geometry const& geometry, Strategy const& strategy) : m_geometry(geometry) , m_strategy(strategy) {} template <typename QueryGeometry> inline bool apply(QueryGeometry const& query_geometry) const { return BinaryPredicate::apply(query_geometry, m_geometry, m_strategy); } private: Geometry const& m_geometry; Strategy const& m_strategy; }; template<typename MultiRange, typename ConstantSizeGeometry> struct multirange_constant_size_geometry { template <typename Strategy> static inline bool apply(MultiRange const& multirange, ConstantSizeGeometry const& constant_size_geometry, Strategy const& strategy) { typedef unary_disjoint_geometry_to_query_geometry < ConstantSizeGeometry, Strategy, dispatch::disjoint < typename boost::range_value<MultiRange>::type, ConstantSizeGeometry > > unary_predicate_type; return detail::check_iterator_range < unary_predicate_type >::apply(boost::begin(multirange), boost::end(multirange), unary_predicate_type(constant_size_geometry, strategy)); } template <typename Strategy> static inline bool apply(ConstantSizeGeometry const& constant_size_geometry, MultiRange const& multirange, Strategy const& strategy) { return apply(multirange, constant_size_geometry, strategy); } }; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP detail/disjoint/point_geometry.hpp 0000644 00000005015 15125631657 0013422 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013, 2014, 2015. // Modifications copyright (c) 2013-2015, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { struct reverse_covered_by { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return ! geometry::covered_by(geometry1, geometry2, strategy); } }; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template<typename Point, typename Linear, std::size_t DimensionCount> struct disjoint<Point, Linear, DimensionCount, point_tag, linear_tag, false> : detail::disjoint::reverse_covered_by {}; template <typename Point, typename Areal, std::size_t DimensionCount> struct disjoint<Point, Areal, DimensionCount, point_tag, areal_tag, false> : detail::disjoint::reverse_covered_by {}; template<typename Point, typename Segment, std::size_t DimensionCount> struct disjoint<Point, Segment, DimensionCount, point_tag, segment_tag, false> : detail::disjoint::reverse_covered_by {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP detail/disjoint/linear_areal.hpp 0000644 00000022534 15125631657 0013001 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP #include <iterator> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { template <typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag1OrMulti = typename tag_cast<Tag1, multi_tag>::type> struct disjoint_no_intersections_policy { /*! \tparam Strategy point_in_geometry strategy */ template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { typedef typename point_type<Geometry1>::type point1_type; point1_type p; geometry::point_on_border(p, g1); return !geometry::covered_by(p, g2, strategy); } }; template <typename Geometry1, typename Geometry2, typename Tag1> struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag> { /*! \tparam Strategy point_in_geometry strategy */ template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { // TODO: use partition or rtree on g2 typedef typename boost::range_iterator<Geometry1 const>::type iterator; for ( iterator it = boost::begin(g1) ; it != boost::end(g1) ; ++it ) { typedef typename boost::range_value<Geometry1 const>::type value_type; if ( ! disjoint_no_intersections_policy<value_type const, Geometry2> ::apply(*it, g2, strategy) ) { return false; } } return true; } }; template<typename Geometry1, typename Geometry2, typename NoIntersectionsPolicy = disjoint_no_intersections_policy<Geometry1, Geometry2> > struct disjoint_linear_areal { /*! \tparam Strategy relate (segments intersection) strategy */ template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { // if there are intersections - return false if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2, strategy) ) { return false; } return NoIntersectionsPolicy ::apply(g1, g2, strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>()); } }; template < typename Segment, typename Areal, typename Tag = typename tag<Areal>::type > struct disjoint_segment_areal : not_implemented<Segment, Areal> {}; template <typename Segment, typename Polygon> class disjoint_segment_areal<Segment, Polygon, polygon_tag> { private: template <typename InteriorRings, typename Strategy> static inline bool check_interior_rings(InteriorRings const& interior_rings, Segment const& segment, Strategy const& strategy) { typedef typename boost::range_value<InteriorRings>::type ring_type; typedef unary_disjoint_geometry_to_query_geometry < Segment, Strategy, disjoint_range_segment_or_box < ring_type, closure<ring_type>::value, Segment > > unary_predicate_type; return check_iterator_range < unary_predicate_type >::apply(boost::begin(interior_rings), boost::end(interior_rings), unary_predicate_type(segment, strategy)); } public: template <typename IntersectionStrategy> static inline bool apply(Segment const& segment, Polygon const& polygon, IntersectionStrategy const& strategy) { typedef typename geometry::ring_type<Polygon>::type ring; if ( !disjoint_range_segment_or_box < ring, closure<Polygon>::value, Segment >::apply(geometry::exterior_ring(polygon), segment, strategy) ) { return false; } if ( !check_interior_rings(geometry::interior_rings(polygon), segment, strategy) ) { return false; } typename point_type<Segment>::type p; detail::assign_point_from_index<0>(segment, p); return !geometry::covered_by(p, polygon, strategy.template get_point_in_geometry_strategy<Segment, Polygon>()); } }; template <typename Segment, typename MultiPolygon> struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag> { template <typename IntersectionStrategy> static inline bool apply(Segment const& segment, MultiPolygon const& multipolygon, IntersectionStrategy const& strategy) { return multirange_constant_size_geometry < MultiPolygon, Segment >::apply(multipolygon, segment, strategy); } }; template <typename Segment, typename Ring> struct disjoint_segment_areal<Segment, Ring, ring_tag> { template <typename IntersectionStrategy> static inline bool apply(Segment const& segment, Ring const& ring, IntersectionStrategy const& strategy) { if ( !disjoint_range_segment_or_box < Ring, closure<Ring>::value, Segment >::apply(ring, segment, strategy) ) { return false; } typename point_type<Segment>::type p; detail::assign_point_from_index<0>(segment, p); return !geometry::covered_by(p, ring, strategy.template get_point_in_geometry_strategy<Segment, Ring>()); } }; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear, typename Areal> struct disjoint<Linear, Areal, 2, linear_tag, areal_tag, false> : public detail::disjoint::disjoint_linear_areal<Linear, Areal> {}; template <typename Areal, typename Linear> struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false> { template <typename Strategy> static inline bool apply(Areal const& areal, Linear const& linear, Strategy const& strategy) { return detail::disjoint::disjoint_linear_areal < Linear, Areal >::apply(linear, areal, strategy); } }; template <typename Areal, typename Segment> struct disjoint<Areal, Segment, 2, areal_tag, segment_tag, false> { template <typename Strategy> static inline bool apply(Areal const& g1, Segment const& g2, Strategy const& strategy) { return detail::disjoint::disjoint_segment_areal < Segment, Areal >::apply(g2, g1, strategy); } }; template <typename Segment, typename Areal> struct disjoint<Segment, Areal, 2, segment_tag, areal_tag, false> : detail::disjoint::disjoint_segment_areal<Segment, Areal> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP detail/disjoint/implementation.hpp 0000644 00000003444 15125631657 0013407 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/disjoint/areal_areal.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_areal.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp> #include <boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP detail/disjoint/segment_box.hpp 0000644 00000023635 15125631657 0012700 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP #include <cstddef> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/radian_access.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/envelope/segment.hpp> #include <boost/geometry/algorithms/detail/normalize.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/formulas/vertex_longitude.hpp> #include <boost/geometry/geometries/box.hpp> // Temporary, for envelope_segment_impl #include <boost/geometry/strategy/spherical/envelope_segment.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { template <typename CS_Tag> struct disjoint_segment_box_sphere_or_spheroid { struct disjoint_info { enum type { intersect, disjoint_no_vertex, disjoint_vertex }; disjoint_info(type t) : m_(t){} operator type () const {return m_;} type m_; private : //prevent automatic conversion for any other built-in types template <typename T> operator T () const; }; template < typename Segment, typename Box, typename AzimuthStrategy, typename NormalizeStrategy, typename DisjointPointBoxStrategy, typename DisjointBoxBoxStrategy > static inline bool apply(Segment const& segment, Box const& box, AzimuthStrategy const& azimuth_strategy, NormalizeStrategy const& normalize_strategy, DisjointPointBoxStrategy const& disjoint_point_box_strategy, DisjointBoxBoxStrategy const& disjoint_box_box_strategy) { typedef typename point_type<Segment>::type segment_point; segment_point vertex; return apply(segment, box, vertex, azimuth_strategy, normalize_strategy, disjoint_point_box_strategy, disjoint_box_box_strategy) != disjoint_info::intersect; } template < typename Segment, typename Box, typename P, typename AzimuthStrategy, typename NormalizeStrategy, typename DisjointPointBoxStrategy, typename DisjointBoxBoxStrategy > static inline disjoint_info apply(Segment const& segment, Box const& box, P& vertex, AzimuthStrategy const& azimuth_strategy, NormalizeStrategy const& , DisjointPointBoxStrategy const& disjoint_point_box_strategy, DisjointBoxBoxStrategy const& disjoint_box_box_strategy) { assert_dimension_equal<Segment, Box>(); typedef typename point_type<Segment>::type segment_point_type; segment_point_type p0, p1; geometry::detail::assign_point_from_index<0>(segment, p0); geometry::detail::assign_point_from_index<1>(segment, p1); //vertex not computed here disjoint_info disjoint_return_value = disjoint_info::disjoint_no_vertex; // Simplest cases first // Case 1: if box contains one of segment's endpoints then they are not disjoint if ( ! disjoint_point_box(p0, box, disjoint_point_box_strategy) || ! disjoint_point_box(p1, box, disjoint_point_box_strategy) ) { return disjoint_info::intersect; } // Case 2: disjoint if bounding boxes are disjoint typedef typename coordinate_type<segment_point_type>::type CT; segment_point_type p0_normalized; NormalizeStrategy::apply(p0, p0_normalized); segment_point_type p1_normalized; NormalizeStrategy::apply(p1, p1_normalized); CT lon1 = geometry::get_as_radian<0>(p0_normalized); CT lat1 = geometry::get_as_radian<1>(p0_normalized); CT lon2 = geometry::get_as_radian<0>(p1_normalized); CT lat2 = geometry::get_as_radian<1>(p1_normalized); if (lon1 > lon2) { std::swap(lon1, lon2); std::swap(lat1, lat2); } geometry::model::box<segment_point_type> box_seg; strategy::envelope::detail::envelope_segment_impl < CS_Tag >::template apply<geometry::radian>(lon1, lat1, lon2, lat2, box_seg, azimuth_strategy); if (disjoint_box_box(box, box_seg, disjoint_box_box_strategy)) { return disjoint_return_value; } // Case 3: test intersection by comparing angles CT alp1, a_b0, a_b1, a_b2, a_b3; CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box); CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box); CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box); CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box); azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1); azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0); azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1); azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2); azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3); bool b0 = formula::azimuth_side_value(alp1, a_b0) > 0; bool b1 = formula::azimuth_side_value(alp1, a_b1) > 0; bool b2 = formula::azimuth_side_value(alp1, a_b2) > 0; bool b3 = formula::azimuth_side_value(alp1, a_b3) > 0; if (!(b0 && b1 && b2 && b3) && (b0 || b1 || b2 || b3)) { return disjoint_info::intersect; } // Case 4: The only intersection case not covered above is when all four // points of the box are above (below) the segment in northern (southern) // hemisphere. Then we have to compute the vertex of the segment CT vertex_lat; CT lat_sum = lat1 + lat2; if ((lat1 < b_lat_min && lat_sum > CT(0)) || (lat1 > b_lat_max && lat_sum < CT(0))) { CT b_lat_below; //latitude of box closest to equator if (lat_sum > CT(0)) { vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg); b_lat_below = b_lat_min; } else { vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg); b_lat_below = b_lat_max; } //optimization TODO: computing the spherical longitude should suffice for // the majority of cases CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag> ::apply(lon1, lat1, lon2, lat2, vertex_lat, alp1, azimuth_strategy); geometry::set_from_radian<0>(vertex, vertex_lon); geometry::set_from_radian<1>(vertex, vertex_lat); disjoint_return_value = disjoint_info::disjoint_vertex; //vertex_computed // Check if the vertex point is within the band defined by the // minimum and maximum longitude of the box; if yes, then return // false if the point is above the min latitude of the box; return // true in all other cases if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max && std::abs(vertex_lat) > std::abs(b_lat_below)) { return disjoint_info::intersect; } } return disjoint_return_value; } }; struct disjoint_segment_box { template <typename Segment, typename Box, typename Strategy> static inline bool apply(Segment const& segment, Box const& box, Strategy const& strategy) { return strategy.apply(segment, box); } }; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Segment, typename Box, std::size_t DimensionCount> struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false> : detail::disjoint::disjoint_segment_box {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP detail/disjoint/areal_areal.hpp 0000644 00000012147 15125631657 0012612 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/for_each_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp> #include <boost/geometry/algorithms/for_each.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { template <typename Geometry1, typename Geometry2, typename Strategy> inline bool point_on_border_covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typename geometry::point_type<Geometry1>::type pt; return geometry::point_on_border(pt, geometry1) && geometry::covered_by(pt, geometry2, strategy); } /*! \tparam Strategy point_in_geometry strategy */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool rings_containing(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // TODO: This will be removed when IntersectionStrategy is replaced with // UmbrellaStrategy auto const pgs = strategy.template get_point_in_geometry_strategy<Geometry2, Geometry1>(); return geometry::detail::any_range_of(geometry2, [&](auto const& range) { return point_on_border_covered_by(range, geometry1, pgs); }); } template <typename Geometry1, typename Geometry2> struct areal_areal { /*! \tparam Strategy relate (segments intersection) strategy */ template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { if ( ! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy) ) { return false; } // If there is no intersection of segments, they might located // inside each other // We check that using a point on the border (external boundary), // and see if that is contained in the other geometry. And vice versa. if ( rings_containing(geometry1, geometry2, strategy) || rings_containing(geometry2, geometry1, strategy) ) { return false; } return true; } }; template <typename Areal, typename Box> struct areal_box { /*! \tparam Strategy relate (segments intersection) strategy */ template <typename Strategy> static inline bool apply(Areal const& areal, Box const& box, Strategy const& strategy) { // TODO: This will be removed when UmbrellaStrategy is supported auto const ds = strategy.get_disjoint_segment_box_strategy(); if (! geometry::all_segments_of(areal, [&](auto const& s) { return disjoint_segment_box::apply(s, box, ds); }) ) { return false; } // If there is no intersection of any segment and box, // the box might be located inside areal geometry if ( point_on_border_covered_by(box, areal, strategy.template get_point_in_geometry_strategy<Box, Areal>()) ) { return false; } return true; } }; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Areal1, typename Areal2> struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false> : detail::disjoint::areal_areal<Areal1, Areal2> {}; template <typename Areal, typename Box> struct disjoint<Areal, Box, 2, areal_tag, box_tag, false> : detail::disjoint::areal_box<Areal, Box> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP detail/disjoint/linear_segment_or_box.hpp 0000644 00000013455 15125631657 0014731 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP #include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { template < typename SegmentOrBox, typename Tag = typename tag<SegmentOrBox>::type > struct disjoint_point_segment_or_box : not_implemented<Tag> {}; template <typename Segment> struct disjoint_point_segment_or_box<Segment, segment_tag> { template <typename Point, typename Strategy> static inline bool apply(Point const& point, Segment const& segment, Strategy const& strategy) { return dispatch::disjoint < Point, Segment >::apply(point, segment, strategy.template get_point_in_geometry_strategy<Point, Segment>()); } }; template <typename Box> struct disjoint_point_segment_or_box<Box, box_tag> { template <typename Point, typename Strategy> static inline bool apply(Point const& point, Box const& box, Strategy const& strategy) { return dispatch::disjoint < Point, Box >::apply(point, box, strategy.get_disjoint_point_box_strategy()); } }; template < typename Range, closure_selector Closure, typename SegmentOrBox > struct disjoint_range_segment_or_box { template <typename Strategy> static inline bool apply(Range const& range, SegmentOrBox const& segment_or_box, Strategy const& strategy) { typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename ::boost::range_value<view_type>::type point_type; typedef typename ::boost::range_iterator < view_type const >::type const_iterator; typedef typename ::boost::range_size<view_type>::type size_type; typedef typename geometry::model::referring_segment < point_type const > range_segment; view_type view(range); const size_type count = ::boost::size(view); if ( count == 0 ) { return false; } else if ( count == 1 ) { return disjoint_point_segment_or_box < SegmentOrBox >::apply(geometry::range::front<view_type const>(view), segment_or_box, strategy); } else { const_iterator it0 = ::boost::begin(view); const_iterator it1 = ::boost::begin(view) + 1; const_iterator last = ::boost::end(view); for ( ; it1 != last ; ++it0, ++it1 ) { point_type const& p0 = *it0; point_type const& p1 = *it1; range_segment rng_segment(p0, p1); if ( !dispatch::disjoint < range_segment, SegmentOrBox >::apply(rng_segment, segment_or_box, strategy) ) { return false; } } return true; } } }; template < typename Linear, typename SegmentOrBox, typename Tag = typename tag<Linear>::type > struct disjoint_linear_segment_or_box : not_implemented<Linear, SegmentOrBox> {}; template <typename Linestring, typename SegmentOrBox> struct disjoint_linear_segment_or_box<Linestring, SegmentOrBox, linestring_tag> : disjoint_range_segment_or_box<Linestring, closed, SegmentOrBox> {}; template <typename MultiLinestring, typename SegmentOrBox> struct disjoint_linear_segment_or_box < MultiLinestring, SegmentOrBox, multi_linestring_tag > : multirange_constant_size_geometry<MultiLinestring, SegmentOrBox> {}; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear, typename Segment> struct disjoint<Linear, Segment, 2, linear_tag, segment_tag, false> : detail::disjoint::disjoint_linear_segment_or_box<Linear, Segment> {}; template <typename Linear, typename Box, std::size_t DimensionCount> struct disjoint<Linear, Box, DimensionCount, linear_tag, box_tag, false> : detail::disjoint::disjoint_linear_segment_or_box<Linear, Box> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP detail/disjoint/multipoint_geometry.hpp 0000644 00000046104 15125631657 0014501 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP #include <algorithm> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/iterators/segment_iterator.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> #include <boost/geometry/policies/compare.hpp> // TEMP #include <boost/geometry/strategies/envelope/cartesian.hpp> #include <boost/geometry/strategies/envelope/geographic.hpp> #include <boost/geometry/strategies/envelope/spherical.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { class multipoint_multipoint { private: template <typename Iterator, typename CSTag> class unary_disjoint_predicate : geometry::less<void, -1, CSTag> { private: typedef geometry::less<void, -1, CSTag> base_type; public: unary_disjoint_predicate(Iterator first, Iterator last) : base_type(), m_first(first), m_last(last) {} template <typename Point> inline bool apply(Point const& point) const { return !std::binary_search(m_first, m_last, point, static_cast<base_type const&>(*this)); } private: Iterator m_first, m_last; }; public: template <typename MultiPoint1, typename MultiPoint2, typename Strategy> static inline bool apply(MultiPoint1 const& multipoint1, MultiPoint2 const& multipoint2, Strategy const&) { typedef typename Strategy::cs_tag cs_tag; typedef geometry::less<void, -1, cs_tag> less_type; BOOST_GEOMETRY_ASSERT( boost::size(multipoint1) <= boost::size(multipoint2) ); typedef typename boost::range_value<MultiPoint1>::type point1_type; std::vector<point1_type> points1(boost::begin(multipoint1), boost::end(multipoint1)); std::sort(points1.begin(), points1.end(), less_type()); typedef unary_disjoint_predicate < typename std::vector<point1_type>::const_iterator, cs_tag > predicate_type; return check_iterator_range < predicate_type >::apply(boost::begin(multipoint2), boost::end(multipoint2), predicate_type(points1.begin(), points1.end())); } }; template <typename MultiPoint, typename Linear> class multipoint_linear { private: template <typename ExpandPointBoxStrategy> struct expand_box_point { template <typename Box, typename Point> static inline void apply(Box& total, Point const& point) { geometry::expand(total, point, ExpandPointBoxStrategy()); } }; template <typename EnvelopeStrategy> struct expand_box_segment { explicit expand_box_segment(EnvelopeStrategy const& strategy) : m_strategy(strategy) {} template <typename Box, typename Segment> inline void apply(Box& total, Segment const& segment) const { geometry::expand(total, geometry::return_envelope<Box>(segment, m_strategy), // TEMP - envelope umbrella strategy also contains // expand strategies strategies::envelope::services::strategy_converter < EnvelopeStrategy >::get(m_strategy)); } EnvelopeStrategy const& m_strategy; }; template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { // The default strategy is enough in this case return ! detail::disjoint::disjoint_point_box(point, box, DisjointPointBoxStrategy()); } }; template <typename DisjointStrategy> struct overlaps_box_segment { explicit overlaps_box_segment(DisjointStrategy const& strategy) : m_strategy(strategy) {} template <typename Box, typename Segment> inline bool apply(Box const& box, Segment const& segment) const { return ! dispatch::disjoint<Segment, Box>::apply(segment, box, m_strategy); } DisjointStrategy const& m_strategy; }; template <typename PtSegStrategy> class item_visitor_type { public: item_visitor_type(PtSegStrategy const& strategy) : m_intersection_found(false) , m_strategy(strategy) {} template <typename Item1, typename Item2> inline bool apply(Item1 const& item1, Item2 const& item2) { if (! m_intersection_found && ! dispatch::disjoint<Item1, Item2>::apply(item1, item2, m_strategy)) { m_intersection_found = true; return false; } return true; } inline bool intersection_found() const { return m_intersection_found; } private: bool m_intersection_found; PtSegStrategy const& m_strategy; }; // structs for partition -- end class segment_range { public: typedef geometry::segment_iterator<Linear const> const_iterator; typedef const_iterator iterator; segment_range(Linear const& linear) : m_linear(linear) {} const_iterator begin() const { return geometry::segments_begin(m_linear); } const_iterator end() const { return geometry::segments_end(m_linear); } private: Linear const& m_linear; }; public: template <typename Strategy> static inline bool apply(MultiPoint const& multipoint, Linear const& linear, Strategy const& strategy) { item_visitor_type<Strategy> visitor(strategy); typedef typename Strategy::expand_point_strategy_type expand_point_strategy_type; typedef typename Strategy::envelope_strategy_type envelope_strategy_type; typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type; typedef typename Strategy::disjoint_point_box_strategy_type disjoint_pb_strategy_type; // TODO: disjoint Segment/Box may be called in partition multiple times // possibly for non-cartesian segments which could be slow. We should consider // passing a range of bounding boxes of segments after calculating them once. // Alternatively instead of a range of segments a range of Segment/Envelope pairs // should be passed, where envelope would be lazily calculated when needed the first time geometry::partition < geometry::model::box<typename point_type<MultiPoint>::type> >::apply(multipoint, segment_range(linear), visitor, expand_box_point<expand_point_strategy_type>(), overlaps_box_point<disjoint_pb_strategy_type>(), expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()), overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy())); return ! visitor.intersection_found(); } template <typename Strategy> static inline bool apply(Linear const& linear, MultiPoint const& multipoint, Strategy const& strategy) { return apply(multipoint, linear, strategy); } }; template <typename MultiPoint, typename SingleGeometry> class multi_point_single_geometry { public: template <typename Strategy> static inline bool apply(MultiPoint const& multi_point, SingleGeometry const& single_geometry, Strategy const& strategy) { typedef typename Strategy::disjoint_point_box_strategy_type d_pb_strategy_type; typedef typename point_type<MultiPoint>::type point1_type; typedef typename point_type<SingleGeometry>::type point2_type; typedef model::box<point2_type> box2_type; box2_type box2; geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy()); geometry::detail::expand_by_epsilon(box2); typedef typename boost::range_const_iterator<MultiPoint>::type iterator; for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) { // The default strategy is enough for Point/Box if (! detail::disjoint::disjoint_point_box(*it, box2, d_pb_strategy_type()) && ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy)) { return false; } } return true; } template <typename Strategy> static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point, Strategy const& strategy) { return apply(multi_point, single_geometry, strategy); } }; template <typename MultiPoint, typename MultiGeometry> class multi_point_multi_geometry { private: template <typename ExpandPointStrategy> struct expand_box_point { template <typename Box, typename Point> static inline void apply(Box& total, Point const& point) { geometry::expand(total, point, ExpandPointStrategy()); } }; template <typename ExpandBoxStrategy> struct expand_box_box_pair { template <typename Box, typename BoxPair> inline void apply(Box& total, BoxPair const& box_pair) const { geometry::expand(total, box_pair.first, ExpandBoxStrategy()); } }; template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { // The default strategy is enough for Point/Box return ! detail::disjoint::disjoint_point_box(point, box, DisjointPointBoxStrategy()); } }; template <typename DisjointBoxBoxStrategy> struct overlaps_box_box_pair { template <typename Box, typename BoxPair> inline bool apply(Box const& box, BoxPair const& box_pair) const { // The default strategy is enough for Box/Box return ! detail::disjoint::disjoint_box_box(box_pair.first, box, DisjointBoxBoxStrategy()); } }; template <typename PtSegStrategy> class item_visitor_type { public: item_visitor_type(MultiGeometry const& multi_geometry, PtSegStrategy const& strategy) : m_intersection_found(false) , m_multi_geometry(multi_geometry) , m_strategy(strategy) {} template <typename Point, typename BoxPair> inline bool apply(Point const& point, BoxPair const& box_pair) { typedef typename PtSegStrategy::disjoint_point_box_strategy_type d_pb_strategy_type; typedef typename boost::range_value<MultiGeometry>::type single_type; // The default strategy is enough for Point/Box if (! m_intersection_found && ! detail::disjoint::disjoint_point_box(point, box_pair.first, d_pb_strategy_type()) && ! dispatch::disjoint<Point, single_type>::apply(point, range::at(m_multi_geometry, box_pair.second), m_strategy)) { m_intersection_found = true; return false; } return true; } inline bool intersection_found() const { return m_intersection_found; } private: bool m_intersection_found; MultiGeometry const& m_multi_geometry; PtSegStrategy const& m_strategy; }; // structs for partition -- end public: template <typename Strategy> static inline bool apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Strategy const& strategy) { typedef typename point_type<MultiPoint>::type point1_type; typedef typename point_type<MultiGeometry>::type point2_type; typedef model::box<point1_type> box1_type; typedef model::box<point2_type> box2_type; typedef std::pair<box2_type, std::size_t> box_pair_type; typename Strategy::envelope_strategy_type const envelope_strategy = strategy.get_envelope_strategy(); std::size_t count2 = boost::size(multi_geometry); std::vector<box_pair_type> boxes(count2); for (std::size_t i = 0 ; i < count2 ; ++i) { geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy); geometry::detail::expand_by_epsilon(boxes[i].first); boxes[i].second = i; } item_visitor_type<Strategy> visitor(multi_geometry, strategy); typedef expand_box_point < typename Strategy::expand_point_strategy_type > expand_box_point_type; typedef overlaps_box_point < typename Strategy::disjoint_point_box_strategy_type > overlaps_box_point_type; typedef expand_box_box_pair < // TEMP - envelope umbrella strategy also contains // expand strategies decltype(strategies::envelope::services::strategy_converter < typename Strategy::envelope_strategy_type >::get(strategy.get_envelope_strategy()) .expand(std::declval<box1_type>(), std::declval<box2_type>())) > expand_box_box_pair_type; typedef overlaps_box_box_pair < typename Strategy::disjoint_box_box_strategy_type > overlaps_box_box_pair_type; geometry::partition < box1_type >::apply(multi_point, boxes, visitor, expand_box_point_type(), overlaps_box_point_type(), expand_box_box_pair_type(), overlaps_box_box_pair_type()); return ! visitor.intersection_found(); } template <typename Strategy> static inline bool apply(MultiGeometry const& multi_geometry, MultiPoint const& multi_point, Strategy const& strategy) { return apply(multi_point, multi_geometry, strategy); } }; template <typename MultiPoint, typename Areal, typename Tag = typename tag<Areal>::type> struct multipoint_areal : multi_point_single_geometry<MultiPoint, Areal> {}; template <typename MultiPoint, typename Areal> struct multipoint_areal<MultiPoint, Areal, multi_polygon_tag> : multi_point_multi_geometry<MultiPoint, Areal> {}; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point, typename MultiPoint, std::size_t DimensionCount> struct disjoint < Point, MultiPoint, DimensionCount, point_tag, multi_point_tag, false > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Point> {}; template <typename MultiPoint, typename Segment, std::size_t DimensionCount> struct disjoint < MultiPoint, Segment, DimensionCount, multi_point_tag, segment_tag, false > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Segment> {}; template <typename MultiPoint, typename Box, std::size_t DimensionCount> struct disjoint < MultiPoint, Box, DimensionCount, multi_point_tag, box_tag, false > : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Box> {}; template < typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount > struct disjoint < MultiPoint1, MultiPoint2, DimensionCount, multi_point_tag, multi_point_tag, false > { template <typename Strategy> static inline bool apply(MultiPoint1 const& multipoint1, MultiPoint2 const& multipoint2, Strategy const& strategy) { if ( boost::size(multipoint2) < boost::size(multipoint1) ) { return detail::disjoint::multipoint_multipoint ::apply(multipoint2, multipoint1, strategy); } return detail::disjoint::multipoint_multipoint ::apply(multipoint1, multipoint2, strategy); } }; template <typename Linear, typename MultiPoint, std::size_t DimensionCount> struct disjoint < Linear, MultiPoint, DimensionCount, linear_tag, multi_point_tag, false > : detail::disjoint::multipoint_linear<MultiPoint, Linear> {}; template <typename MultiPoint, typename Linear, std::size_t DimensionCount> struct disjoint < MultiPoint, Linear, DimensionCount, multi_point_tag, linear_tag, false > : detail::disjoint::multipoint_linear<MultiPoint, Linear> {}; template <typename Areal, typename MultiPoint, std::size_t DimensionCount> struct disjoint < Areal, MultiPoint, DimensionCount, areal_tag, multi_point_tag, false > : detail::disjoint::multipoint_areal<MultiPoint, Areal> {}; template <typename MultiPoint, typename Areal, std::size_t DimensionCount> struct disjoint < MultiPoint, Areal, DimensionCount, multi_point_tag, areal_tag, false > : detail::disjoint::multipoint_areal<MultiPoint, Areal> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP detail/disjoint/interface.hpp 0000644 00000017005 15125631657 0012320 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP #include <cstddef> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/relate/interface.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/disjoint.hpp> namespace boost { namespace geometry { namespace resolve_strategy { struct disjoint { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return dispatch::disjoint < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::disjoint::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return dispatch::disjoint < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct disjoint { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions < Geometry1 const, Geometry2 const >(); return resolve_strategy::disjoint::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct disjoint<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) , m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return disjoint<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct disjoint<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) , m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return disjoint<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template < BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2) > struct disjoint < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return disjoint<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief \brief_check2{are disjoint} \ingroup disjoint \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Disjoint} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{disjoint} \return \return_check2{are disjoint} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/disjoint.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool disjoint(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::disjoint < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief \brief_check2{are disjoint} \ingroup disjoint \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{are disjoint} \qbk{[include reference/algorithms/disjoint.qbk]} \qbk{ [heading Examples] [disjoint] [disjoint_output] } */ template <typename Geometry1, typename Geometry2> inline bool disjoint(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::disjoint < Geometry1, Geometry2 >::apply(geometry1, geometry2, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP detail/disjoint/point_box.hpp 0000644 00000004445 15125631657 0012365 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland // This file was modified by Oracle on 2013-2018. // Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP #include <cstddef> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> #include <boost/geometry/strategies/disjoint.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { /*! \brief Internal utility function to detect if point/box are disjoint */ template <typename Point, typename Box, typename Strategy> inline bool disjoint_point_box(Point const& point, Box const& box, Strategy const& ) { // ! covered_by(point, box) return ! Strategy::apply(point, box); } }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point, typename Box, std::size_t DimensionCount> struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, false> { template <typename Strategy> static inline bool apply(Point const& point, Box const& box, Strategy const& ) { // ! covered_by(point, box) return ! Strategy::apply(point, box); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP detail/disjoint/point_point.hpp 0000644 00000004707 15125631657 0012727 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. // Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP #include <cstddef> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> // For backward compatibility #include <boost/geometry/strategies/disjoint.hpp> #include <boost/geometry/strategies/cartesian/point_in_point.hpp> #include <boost/geometry/strategies/spherical/point_in_point.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { /*! \brief Internal utility function to detect of points are disjoint \note To avoid circular references */ template <typename Point1, typename Point2, typename Strategy> inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2, Strategy const& ) { return ! Strategy::apply(point1, point2); } }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Point1, typename Point2, std::size_t DimensionCount> struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false> { template <typename Strategy> static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& ) { return ! Strategy::apply(point1, point2); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP detail/disjoint/box_box.hpp 0000644 00000004435 15125631657 0012023 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2018. // Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP #include <cstddef> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> // For backward compatibility #include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp> #include <boost/geometry/strategies/spherical/disjoint_box_box.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { /*! \brief Internal utility function to detect if boxes are disjoint \note Is used from other algorithms, declared separately to avoid circular references */ template <typename Box1, typename Box2, typename Strategy> inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2, Strategy const&) { return Strategy::apply(box1, box2); } }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Box1, typename Box2, std::size_t DimensionCount> struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false> { template <typename Strategy> static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const&) { return Strategy::apply(box1, box2); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP detail/disjoint/linear_linear.hpp 0000644 00000012471 15125631657 0013166 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP #include <cstddef> #include <deque> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp> #include <boost/geometry/policies/disjoint_interrupt_policy.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> #include <boost/geometry/algorithms/dispatch/disjoint.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace disjoint { template <typename Segment1, typename Segment2> struct disjoint_segment { template <typename Strategy> static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& strategy) { typedef typename point_type<Segment1>::type point_type; typedef segment_intersection_points<point_type> intersection_return_type; typedef policies::relate::segments_intersection_points < intersection_return_type > intersection_policy; detail::segment_as_subrange<Segment1> sub_range1(segment1); detail::segment_as_subrange<Segment2> sub_range2(segment2); intersection_return_type is = strategy.apply(sub_range1, sub_range2, intersection_policy()); return is.count == 0; } }; struct assign_disjoint_policy { // We want to include all points: static bool const include_no_turn = true; static bool const include_degenerate = true; static bool const include_opposite = true; static bool const include_start_turn = false; }; template <typename Geometry1, typename Geometry2> struct disjoint_linear { template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typedef typename geometry::point_type<Geometry1>::type point_type; typedef geometry::segment_ratio < typename coordinate_type<point_type>::type > ratio_type; typedef overlay::turn_info < point_type, ratio_type, typename detail::get_turns::turn_operation_type < Geometry1, Geometry2, ratio_type >::type > turn_info_type; std::deque<turn_info_type> turns; // Specify two policies: // 1) Stop at any intersection // 2) In assignment, include also degenerate points (which are normally skipped) disjoint_interrupt_policy interrupt_policy; dispatch::get_turns < typename geometry::tag<Geometry1>::type, typename geometry::tag<Geometry2>::type, Geometry1, Geometry2, overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, // should be false overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, // should be false detail::get_turns::get_turn_info_type < Geometry1, Geometry2, assign_disjoint_policy > >::apply(0, geometry1, 1, geometry2, strategy, detail::no_rescale_policy(), turns, interrupt_policy); return !interrupt_policy.has_intersections; } }; }} // namespace detail::disjoint #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Linear1, typename Linear2> struct disjoint<Linear1, Linear2, 2, linear_tag, linear_tag, false> : detail::disjoint::disjoint_linear<Linear1, Linear2> {}; template <typename Segment1, typename Segment2> struct disjoint<Segment1, Segment2, 2, segment_tag, segment_tag, false> : detail::disjoint::disjoint_segment<Segment1, Segment2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP detail/centroid/translating_transformer.hpp 0000644 00000007043 15125631657 0015315 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP #include <cstddef> #include <boost/core/addressof.hpp> #include <boost/core/ref.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/iterators/point_iterator.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace centroid { // NOTE: There is no need to translate in other coordinate systems than // cartesian. But if it was needed then one should translate using // CS-specific technique, e.g. in spherical/geographic a translation // vector should contain coordinates being multiplies of 2PI or 360 deg. template <typename Geometry, typename CastedTag = typename tag_cast < typename tag<Geometry>::type, areal_tag >::type, typename CSTag = typename cs_tag<Geometry>::type> struct translating_transformer { typedef typename geometry::point_type<Geometry>::type point_type; typedef boost::reference_wrapper<point_type const> result_type; explicit translating_transformer(Geometry const&) {} explicit translating_transformer(point_type const&) {} result_type apply(point_type const& pt) const { return result_type(pt); } template <typename ResPt> void apply_reverse(ResPt &) const {} }; // Specialization for Areal Geometries in cartesian CS template <typename Geometry> struct translating_transformer<Geometry, areal_tag, cartesian_tag> { typedef typename geometry::point_type<Geometry>::type point_type; typedef point_type result_type; explicit translating_transformer(Geometry const& geom) : m_origin(NULL) { geometry::point_iterator<Geometry const> pt_it = geometry::points_begin(geom); if ( pt_it != geometry::points_end(geom) ) { m_origin = boost::addressof(*pt_it); } } explicit translating_transformer(point_type const& origin) : m_origin(boost::addressof(origin)) {} result_type apply(point_type const& pt) const { point_type res = pt; if ( m_origin ) geometry::subtract_point(res, *m_origin); return res; } template <typename ResPt> void apply_reverse(ResPt & res_pt) const { if ( m_origin ) geometry::add_point(res_pt, *m_origin); } const point_type * m_origin; }; }} // namespace detail::centroid #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP detail/signed_size_type.hpp 0000644 00000001352 15125631657 0012077 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_SIZE_TYPE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_SIZE_TYPE_HPP #include <cstddef> #include <type_traits> namespace boost { namespace geometry { typedef std::make_signed<std::size_t>::type signed_size_type; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SIGNED_SIZE_TYPE_HPP detail/multi_modify_with_predicate.hpp 0000644 00000003176 15125631657 0014315 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename MultiGeometry, typename Predicate, typename Policy> struct multi_modify_with_predicate { static inline void apply(MultiGeometry& multi, Predicate const& predicate) { typedef typename boost::range_iterator<MultiGeometry>::type iterator_type; for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, predicate); } } }; } // namespace detail #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MULTI_MODIFY_WITH_PREDICATE_HPP detail/azimuth.hpp 0000644 00000011302 15125631657 0010210 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014, 2016, 2017. // Modifications copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/radian_access.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/formulas/spherical.hpp> #include <boost/geometry/formulas/vincenty_inverse.hpp> #include <boost/geometry/srs/spheroid.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { // An azimuth is an angle between a vector/segment from origin to a point of // interest and a reference vector. Typically north-based azimuth is used. // North direction is used as a reference, angle is measured clockwise // (North - 0deg, East - 90deg). For consistency in 2d cartesian CS // the reference vector is Y axis, angle is measured clockwise. // http://en.wikipedia.org/wiki/Azimuth #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { template <typename ReturnType, typename Tag> struct azimuth : not_implemented<Tag> {}; template <typename ReturnType> struct azimuth<ReturnType, geographic_tag> { template <typename P1, typename P2, typename Spheroid> static inline ReturnType apply(P1 const& p1, P2 const& p2, Spheroid const& spheroid) { return geometry::formula::vincenty_inverse<ReturnType, false, true>().apply ( get_as_radian<0>(p1), get_as_radian<1>(p1), get_as_radian<0>(p2), get_as_radian<1>(p2), spheroid ).azimuth; } template <typename P1, typename P2> static inline ReturnType apply(P1 const& p1, P2 const& p2) { return apply(p1, p2, srs::spheroid<ReturnType>()); } }; template <typename ReturnType> struct azimuth<ReturnType, spherical_equatorial_tag> { template <typename P1, typename P2, typename Sphere> static inline ReturnType apply(P1 const& p1, P2 const& p2, Sphere const& /*unused*/) { return geometry::formula::spherical_azimuth<ReturnType, false> ( get_as_radian<0>(p1), get_as_radian<1>(p1), get_as_radian<0>(p2), get_as_radian<1>(p2)).azimuth; } template <typename P1, typename P2> static inline ReturnType apply(P1 const& p1, P2 const& p2) { return apply(p1, p2, 0); // dummy model } }; template <typename ReturnType> struct azimuth<ReturnType, spherical_polar_tag> : azimuth<ReturnType, spherical_equatorial_tag> {}; template <typename ReturnType> struct azimuth<ReturnType, cartesian_tag> { template <typename P1, typename P2, typename Plane> static inline ReturnType apply(P1 const& p1, P2 const& p2, Plane const& /*unused*/) { ReturnType x = get<0>(p2) - get<0>(p1); ReturnType y = get<1>(p2) - get<1>(p1); // NOTE: azimuth 0 is at Y axis, increasing right // as in spherical/geographic where 0 is at North axis return atan2(x, y); } template <typename P1, typename P2> static inline ReturnType apply(P1 const& p1, P2 const& p2) { return apply(p1, p2, 0); // dummy model } }; } // detail_dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { /// Calculate azimuth between two points. /// The result is in radians. template <typename ReturnType, typename Point1, typename Point2> inline ReturnType azimuth(Point1 const& p1, Point2 const& p2) { return detail_dispatch::azimuth < ReturnType, typename geometry::cs_tag<Point1>::type >::apply(p1, p2); } /// Calculate azimuth between two points. /// The result is in radians. template <typename ReturnType, typename Point1, typename Point2, typename Model> inline ReturnType azimuth(Point1 const& p1, Point2 const& p2, Model const& model) { return detail_dispatch::azimuth < ReturnType, typename geometry::cs_tag<Point1>::type >::apply(p1, p2, model); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AZIMUTH_HPP detail/point_is_spike_or_equal.hpp 0000644 00000012517 15125631657 0013446 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2015, 2017, 2019. // Modifications copyright (c) 2015-2019 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP #include <boost/geometry/algorithms/detail/direction_code.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/policies/robustness/robust_point_type.hpp> #include <boost/geometry/strategies/side.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { // Checks if a point ("last_point") causes a spike w.r.t. // the specified two other points (segment_a, segment_b) // // x-------x------x // a lp b // // Above, lp generates a spike w.r.t. segment(a,b) // So specify last point first, then (a,b) // The segment's orientation does matter: if lp is to the right of b // no spike is reported template < typename Point1, typename Point2, typename Point3, typename SideStrategy > inline bool point_is_spike_or_equal(Point1 const& last_point, // prev | back Point2 const& segment_a, // next | back - 2 Point3 const& segment_b, // curr | back - 1 | spike's vertex SideStrategy const& strategy) { typedef typename SideStrategy::cs_tag cs_tag; int const side = strategy.apply(segment_a, segment_b, last_point); if (side == 0) { // Last point is collinear w.r.t previous segment. return direction_code<cs_tag>(segment_a, segment_b, last_point) < 1; } return false; } template < typename Point1, typename Point2, typename Point3, typename SideStrategy, typename RobustPolicy > inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 const& segment_a, Point3 const& segment_b, SideStrategy const& strategy, RobustPolicy const& robust_policy) { if (point_is_spike_or_equal(last_point, segment_a, segment_b, strategy)) { return true; } if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled)) { return false; } // Try using specified robust policy typedef typename geometry::robust_point_type < Point1, RobustPolicy >::type robust_point_type; robust_point_type last_point_rob, segment_a_rob, segment_b_rob; geometry::recalculate(last_point_rob, last_point, robust_policy); geometry::recalculate(segment_a_rob, segment_a, robust_policy); geometry::recalculate(segment_b_rob, segment_b, robust_policy); return point_is_spike_or_equal ( last_point_rob, segment_a_rob, segment_b_rob, strategy ); } template < typename Point1, typename Point2, typename Point3, typename SideStrategy, typename RobustPolicy > inline bool point_is_collinear(Point1 const& last_point, Point2 const& segment_a, Point3 const& segment_b, SideStrategy const& strategy, RobustPolicy const& robust_policy) { int const side = strategy.apply(segment_a, segment_b, last_point); if (side == 0) { return true; } // This part (or whole method, because it is then trivial) // will be removed after rescaling if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled)) { return false; } // Redo, using specified robust policy typedef typename geometry::robust_point_type < Point1, RobustPolicy >::type robust_point_type; robust_point_type last_point_rob, segment_a_rob, segment_b_rob; geometry::recalculate(last_point_rob, last_point, robust_policy); geometry::recalculate(segment_a_rob, segment_a, robust_policy); geometry::recalculate(segment_b_rob, segment_b, robust_policy); int const side_rob = strategy.apply(segment_a_rob, segment_b_rob, last_point_rob); return side_rob == 0; } //! Version with intuitive order (A, B, C). The original order was //! unclear (C, A, B). It was used in a different way in has_spikes. //! On longer term the C,A,B version can be deprecated template < typename Point1, typename Point2, typename Point3, typename SideStrategy > inline bool is_spike_or_equal(Point1 const& a, Point2 const& b, Point3 const& c, SideStrategy const& strategy) { return point_is_spike_or_equal(c, a, b, strategy); } } // namespace detail #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_IS_EQUAL_OR_SPIKE_HPP detail/max_interval_gap.hpp 0000644 00000017552 15125631657 0012064 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_MAX_INTERVAL_GAP_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAX_INTERVAL_GAP_HPP #include <cstddef> #include <functional> #include <queue> #include <utility> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/algorithms/detail/sweep.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace max_interval_gap { // the class Interval must provide the following: // * must define the type value_type // * must define the type difference_type // * must have the methods: // value_type get<Index>() const // difference_type length() const // where an Index value of 0 (resp., 1) refers to the left (resp., // right) endpoint of the interval template <typename Interval> class sweep_event { public: typedef Interval interval_type; typedef typename Interval::value_type time_type; sweep_event(Interval const& interval, bool start_event = true) : m_interval(std::cref(interval)) , m_start_event(start_event) {} inline bool is_start_event() const { return m_start_event; } inline interval_type const& interval() const { return m_interval; } inline time_type time() const { return (m_start_event) ? interval().template get<0>() : interval().template get<1>(); } inline bool operator<(sweep_event const& other) const { if (! math::equals(time(), other.time())) { return time() < other.time(); } // a start-event is before an end-event with the same event time return is_start_event() && ! other.is_start_event(); } private: std::reference_wrapper<Interval const> m_interval; bool m_start_event; }; template <typename Event> struct event_greater { inline bool operator()(Event const& event1, Event const& event2) const { return event2 < event1; } }; struct initialization_visitor { template <typename Range, typename PriorityQueue, typename EventVisitor> static inline void apply(Range const& range, PriorityQueue& queue, EventVisitor&) { BOOST_GEOMETRY_ASSERT(queue.empty()); // it is faster to build the queue directly from the entire // range, rather than insert elements one after the other PriorityQueue pq(boost::begin(range), boost::end(range)); std::swap(pq, queue); } }; template <typename Event> class event_visitor { typedef typename Event::time_type event_time_type; typedef typename Event::interval_type::difference_type difference_type; public: event_visitor() : m_overlap_count(0) , m_max_gap_left(0) , m_max_gap_right(0) {} template <typename PriorityQueue> inline void apply(Event const& event, PriorityQueue& queue) { if (event.is_start_event()) { ++m_overlap_count; queue.push(Event(event.interval(), false)); } else { --m_overlap_count; if (m_overlap_count == 0 && ! queue.empty()) { // we may have a gap BOOST_GEOMETRY_ASSERT(queue.top().is_start_event()); event_time_type next_event_time = queue.top().interval().template get<0>(); difference_type gap = next_event_time - event.time(); if (gap > max_gap()) { m_max_gap_left = event.time(); m_max_gap_right = next_event_time; } } } } event_time_type const& max_gap_left() const { return m_max_gap_left; } event_time_type const& max_gap_right() const { return m_max_gap_right; } difference_type max_gap() const { return m_max_gap_right - m_max_gap_left; } private: std::size_t m_overlap_count; event_time_type m_max_gap_left, m_max_gap_right; }; }} // namespace detail::max_interval_gap #endif // DOXYGEN_NO_DETAIL // Given a range of intervals I1, I2, ..., In, maximum_gap() returns // the maximum length of an interval M that satisfies the following // properties: // // 1. M.left >= min(I1, I2, ..., In) // 2. M.right <= max(I1, I2, ..., In) // 3. intersection(interior(M), Ik) is the empty set for all k=1, ..., n // 4. length(M) is maximal // // where M.left and M.right denote the left and right extreme values // for the interval M, and length(M) is equal to M.right - M.left. // // If M does not exist (or, alternatively, M is identified as the // empty set), 0 is returned. // // The algorithm proceeds for performing a sweep: the left endpoints // are inserted into a min-priority queue with the priority being the // value of the endpoint. The sweep algorithm maintains an "overlap // counter" that counts the number of overlaping intervals at any // specific sweep-time value. // There are two types of events encountered during the sweep: // (a) a start event: the left endpoint of an interval is found. // In this case the overlap count is increased by one and the // right endpoint of the interval in inserted into the event queue // (b) an end event: the right endpoint of an interval is found. // In this case the overlap count is decreased by one. If the // updated overlap count is 0, then we could expect to have a gap // in-between intervals. This gap is measured as the (absolute) // distance of the current interval right endpoint (being // processed) to the upcoming left endpoint of the next interval // to be processed (if such an interval exists). If the measured // gap is greater than the current maximum gap, it is recorded. // The initial maximum gap is initialized to 0. This value is returned // if no gap is found during the sweeping procedure. template <typename RangeOfIntervals, typename T> inline typename boost::range_value<RangeOfIntervals>::type::difference_type maximum_gap(RangeOfIntervals const& range_of_intervals, T& max_gap_left, T& max_gap_right) { typedef typename boost::range_value<RangeOfIntervals>::type interval_type; typedef detail::max_interval_gap::sweep_event<interval_type> event_type; // create a min-priority queue for the events std::priority_queue < event_type, std::vector<event_type>, detail::max_interval_gap::event_greater<event_type> > queue; // define initialization and event-process visitors detail::max_interval_gap::initialization_visitor init_visitor; detail::max_interval_gap::event_visitor<event_type> sweep_visitor; // perform the sweep geometry::sweep(range_of_intervals, queue, init_visitor, sweep_visitor); max_gap_left = sweep_visitor.max_gap_left(); max_gap_right = sweep_visitor.max_gap_right(); return sweep_visitor.max_gap(); } template <typename RangeOfIntervals> inline typename boost::range_value<RangeOfIntervals>::type::difference_type maximum_gap(RangeOfIntervals const& range_of_intervals) { typedef typename boost::range_value<RangeOfIntervals>::type interval_type; typename interval_type::value_type left, right; return maximum_gap(range_of_intervals, left, right); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAX_INTERVAL_GAP_HPP detail/expand_by_epsilon.hpp 0000644 00000007417 15125631657 0012245 0 ustar 00 // Boost.Geometry // Copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_EXPAND_BY_EPSILON_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_EXPAND_BY_EPSILON_HPP #include <algorithm> #include <cstddef> #include <type_traits> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/views/detail/indexed_point_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace expand { template < typename Point, template <typename> class PlusOrMinus, std::size_t I = 0, std::size_t D = dimension<Point>::value > struct corner_by_epsilon { static inline void apply(Point & point) { typedef typename coordinate_type<Point>::type coord_type; coord_type const coord = get<I>(point); coord_type const seps = math::scaled_epsilon(coord); set<I>(point, PlusOrMinus<coord_type>()(coord, seps)); corner_by_epsilon<Point, PlusOrMinus, I+1>::apply(point); } static inline void apply(Point & point, typename coordinate_type<Point>::type const& eps) { typedef typename coordinate_type<Point>::type coord_type; coord_type const coord = get<I>(point); coord_type const seps = math::scaled_epsilon(coord, eps); set<I>(point, PlusOrMinus<coord_type>()(coord, seps)); corner_by_epsilon<Point, PlusOrMinus, I + 1>::apply(point); } }; template < typename Point, template <typename> class PlusOrMinus, std::size_t D > struct corner_by_epsilon<Point, PlusOrMinus, D, D> { static inline void apply(Point const&) {} static inline void apply(Point const&, typename coordinate_type<Point>::type const&) {} }; template < typename Box, bool Enable = ! std::is_integral<typename coordinate_type<Box>::type>::value > struct expand_by_epsilon { static inline void apply(Box & box) { typedef detail::indexed_point_view<Box, min_corner> min_type; min_type min_point(box); corner_by_epsilon<min_type, std::minus>::apply(min_point); typedef detail::indexed_point_view<Box, max_corner> max_type; max_type max_point(box); corner_by_epsilon<max_type, std::plus>::apply(max_point); } static inline void apply(Box & box, typename coordinate_type<Box>::type const& eps) { typedef detail::indexed_point_view<Box, min_corner> min_type; min_type min_point(box); corner_by_epsilon<min_type, std::minus>::apply(min_point, eps); typedef detail::indexed_point_view<Box, max_corner> max_type; max_type max_point(box); corner_by_epsilon<max_type, std::plus>::apply(max_point, eps); } }; template <typename Box> struct expand_by_epsilon<Box, false> { static inline void apply(Box &) {} static inline void apply(Box &, typename coordinate_type<Box>::type const&) {} }; } // namespace expand template <typename Box> inline void expand_by_epsilon(Box & box) { expand::expand_by_epsilon<Box>::apply(box); } template <typename Box> inline void expand_by_epsilon(Box & box, typename coordinate_type<Box>::type const& eps) { expand::expand_by_epsilon<Box>::apply(box, eps); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EXPAND_EXPAND_BY_EPSILON_HPP detail/overlay/turn_info.hpp 0000644 00000010606 15125631657 0012221 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP #include <boost/array.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/policies/robustness/segment_ratio.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { enum method_type { method_none, method_disjoint, method_crosses, method_touch, method_touch_interior, method_collinear, method_equal, method_start, method_error }; /*! \brief Turn operation: operation \details Information necessary for traversal phase (a phase of the overlay process). The information is gathered during the get_turns (segment intersection) phase. The class is to be included in the turn_info class, either direct or a derived or similar class with more (e.g. enrichment) information. */ template <typename Point, typename SegmentRatio> struct turn_operation { typedef SegmentRatio segment_ratio_type; operation_type operation; segment_identifier seg_id; SegmentRatio fraction; typedef typename coordinate_type<Point>::type comparable_distance_type; comparable_distance_type remaining_distance; inline turn_operation() : operation(operation_none) , remaining_distance(0) {} }; /*! \brief Turn information: intersection point, method, and turn information \details Information necessary for traversal phase (a phase of the overlay process). The information is gathered during the get_turns (segment intersection) phase. \tparam Point point type of intersection point \tparam Operation gives classes opportunity to add additional info \tparam Container gives classes opportunity to define how operations are stored */ template < typename Point, typename SegmentRatio = geometry::segment_ratio<typename coordinate_type<Point>::type>, typename Operation = turn_operation<Point, SegmentRatio>, typename Container = boost::array<Operation, 2> > struct turn_info { typedef Point point_type; typedef SegmentRatio segment_ratio_type; typedef Operation turn_operation_type; typedef Container container_type; Point point; method_type method; bool touch_only; // True in case of method touch(interior) and lines do not cross signed_size_type cluster_id; // For multiple turns on same location, > 0. Else -1. 0 is unused. bool discarded; bool has_colocated_both; // Colocated with a uu turn (for union) or ii (other) Container operations; inline turn_info() : method(method_none) , touch_only(false) , cluster_id(-1) , discarded(false) , has_colocated_both(false) {} inline bool both(operation_type type) const { return has12(type, type); } inline bool has(operation_type type) const { return this->operations[0].operation == type || this->operations[1].operation == type; } inline bool combination(operation_type type1, operation_type type2) const { return has12(type1, type2) || has12(type2, type1); } inline bool blocked() const { return both(operation_blocked); } inline bool opposite() const { return both(operation_opposite); } inline bool any_blocked() const { return has(operation_blocked); } inline bool is_clustered() const { return cluster_id > 0; } private : inline bool has12(operation_type type1, operation_type type2) const { return this->operations[0].operation == type1 && this->operations[1].operation == type2 ; } }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP detail/overlay/self_turn_points.hpp 0000644 00000025000 15125631657 0013605 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP #include <cstddef> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace self_get_turn_points { struct no_interrupt_policy { static bool const enabled = false; static bool const has_intersections = false; template <typename Range> static inline bool apply(Range const&) { return false; } }; template < bool Reverse, typename Geometry, typename Turns, typename TurnPolicy, typename IntersectionStrategy, typename RobustPolicy, typename InterruptPolicy > struct self_section_visitor { Geometry const& m_geometry; IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; int m_source_index; bool m_skip_adjacent; inline self_section_visitor(Geometry const& g, IntersectionStrategy const& is, RobustPolicy const& rp, Turns& turns, InterruptPolicy& ip, int source_index, bool skip_adjacent) : m_geometry(g) , m_intersection_strategy(is) , m_rescale_policy(rp) , m_turns(turns) , m_interrupt_policy(ip) , m_source_index(source_index) , m_skip_adjacent(skip_adjacent) {} template <typename Section> inline bool apply(Section const& sec1, Section const& sec2) { if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box, m_intersection_strategy.get_disjoint_box_box_strategy()) && ! sec1.duplicate && ! sec2.duplicate) { // false if interrupted return detail::get_turns::get_turns_in_sections < Geometry, Geometry, Reverse, Reverse, Section, Section, TurnPolicy >::apply(m_source_index, m_geometry, sec1, m_source_index, m_geometry, sec2, false, m_skip_adjacent, m_intersection_strategy, m_rescale_policy, m_turns, m_interrupt_policy); } return true; } }; template <bool Reverse, typename TurnPolicy> struct get_turns { template <typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( Geometry const& geometry, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int source_index, bool skip_adjacent) { typedef model::box < typename geometry::robust_point_type < typename geometry::point_type<Geometry>::type, RobustPolicy >::type > box_type; // sectionalize in two dimensions to detect // all potential spikes correctly typedef geometry::sections<box_type, 2> sections_type; typedef std::integer_sequence<std::size_t, 0, 1> dimensions; sections_type sec; geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec, intersection_strategy.get_envelope_strategy(), intersection_strategy.get_expand_strategy()); self_section_visitor < Reverse, Geometry, Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent); typedef detail::section::get_section_box < typename IntersectionStrategy::expand_box_strategy_type > get_section_box_type; typedef detail::section::overlaps_section_box < typename IntersectionStrategy::disjoint_box_box_strategy_type > overlaps_section_box_type; // false if interrupted geometry::partition < box_type >::apply(sec, visitor, get_section_box_type(), overlaps_section_box_type()); return ! interrupt_policy.has_intersections; } }; }} // namespace detail::self_get_turn_points #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < bool Reverse, typename GeometryTag, typename Geometry, typename TurnPolicy > struct self_get_turn_points { }; template < bool Reverse, typename Ring, typename TurnPolicy > struct self_get_turn_points < Reverse, ring_tag, Ring, TurnPolicy > : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy> {}; template < bool Reverse, typename Box, typename TurnPolicy > struct self_get_turn_points < Reverse, box_tag, Box, TurnPolicy > { template <typename Strategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( Box const& , Strategy const& , RobustPolicy const& , Turns& , InterruptPolicy& , int /*source_index*/, bool /*skip_adjacent*/) { return true; } }; template < bool Reverse, typename Polygon, typename TurnPolicy > struct self_get_turn_points < Reverse, polygon_tag, Polygon, TurnPolicy > : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy> {}; template < bool Reverse, typename MultiPolygon, typename TurnPolicy > struct self_get_turn_points < Reverse, multi_polygon_tag, MultiPolygon, TurnPolicy > : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace self_get_turn_points { // Version where Reverse can be specified manually. TODO: // can most probably be merged with self_get_turn_points::get_turn template < bool Reverse, typename AssignPolicy, typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, IntersectionStrategy const& strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int source_index = 0, bool skip_adjacent = false) { concepts::check<Geometry const>(); typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy; dispatch::self_get_turn_points < Reverse, typename tag<Geometry>::type, Geometry, turn_policy >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent); } }} // namespace detail::self_get_turn_points #endif // DOXYGEN_NO_DETAIL /*! \brief Calculate self intersections of a geometry \ingroup overlay \tparam Geometry geometry type \tparam Turns type of intersection container (e.g. vector of "intersection/turn point"'s) \param geometry geometry \param strategy strategy to be used \param robust_policy policy to handle robustness issues \param turns container which will contain intersection points \param interrupt_policy policy determining if process is stopped when intersection is found \param source_index source index for generated turns \param skip_adjacent indicates if adjacent turns should be skipped */ template < typename AssignPolicy, typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, IntersectionStrategy const& strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int source_index = 0, bool skip_adjacent = false) { concepts::check<Geometry const>(); static bool const reverse = detail::overlay::do_reverse < geometry::point_order<Geometry>::value >::value; detail::self_get_turn_points::self_turns < reverse, AssignPolicy >(geometry, strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP detail/overlay/check_enrich.hpp 0000644 00000012361 15125631657 0012623 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018. // Modifications copyright (c) 2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP #ifdef BOOST_GEOMETRY_DEBUG_ENRICH #include <iostream> #endif // BOOST_GEOMETRY_DEBUG_ENRICH #include <cstddef> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template<typename Turn> struct meta_turn { int index; Turn const* turn; bool handled[2]; inline meta_turn(int i, Turn const& t) : index(i), turn(&t) { handled[0] = false; handled[1] = false; } }; template <typename MetaTurn> inline void display(MetaTurn const& meta_turn, const char* reason = "") { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout << meta_turn.index << "\tMethods: " << method_char(meta_turn.turn->method) << " operations: " << operation_char(meta_turn.turn->operations[0].operation) << operation_char(meta_turn.turn->operations[1].operation) << " travels to " << meta_turn.turn->operations[0].enriched.travels_to_ip_index << " and " << meta_turn.turn->operations[1].enriched.travels_to_ip_index //<< " -> " << op_index << " " << reason << std::endl; #endif } template <typename MetaTurns, typename MetaTurn> inline void check_detailed(MetaTurns& meta_turns, MetaTurn const& meta_turn, int op_index, int cycle, int start, operation_type for_operation, bool& error) { display(meta_turn); int const ip_index = meta_turn.turn->operations[op_index].enriched.travels_to_ip_index; if (ip_index >= 0) { bool found = false; if (ip_index == start) { display(meta_turns[ip_index], " FINISH"); return; } // check on continuing, or on same-operation-on-same-geometry if (! meta_turns[ip_index].handled[op_index] && (meta_turns[ip_index].turn->operations[op_index].operation == operation_continue || meta_turns[ip_index].turn->operations[op_index].operation == for_operation) ) { meta_turns[ip_index].handled[op_index] = true; check_detailed(meta_turns, meta_turns[ip_index], op_index, cycle, start, for_operation, error); found = true; } // check on other geometry if (! found) { int const other_index = 1 - op_index; if (! meta_turns[ip_index].handled[other_index] && meta_turns[ip_index].turn->operations[other_index].operation == for_operation) { meta_turns[ip_index].handled[other_index] = true; check_detailed(meta_turns, meta_turns[ip_index], other_index, cycle, start, for_operation, error); found = true; } } if (! found) { display(meta_turns[ip_index], " STOP"); error = true; #ifndef BOOST_GEOMETRY_DEBUG_ENRICH //std::cout << " STOP"; #endif } } } template <typename TurnPoints> inline bool check_graph(TurnPoints& turn_points, operation_type for_operation) { typedef typename boost::range_value<TurnPoints>::type turn_point_type; bool error = false; int index = 0; std::vector<meta_turn<turn_point_type> > meta_turns; for (typename boost::range_iterator<TurnPoints const>::type it = boost::begin(turn_points); it != boost::end(turn_points); ++it, ++index) { meta_turns.push_back(meta_turn<turn_point_type>(index, *it)); } int cycle = 0; for (typename boost::range_iterator<std::vector<meta_turn<turn_point_type> > > ::type it = boost::begin(meta_turns); it != boost::end(meta_turns); ++it) { if (! (it->turn->blocked() || it->turn->discarded)) { for (int i = 0 ; i < 2; i++) { if (! it->handled[i] && it->turn->operations[i].operation == for_operation) { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout << "CYCLE " << cycle << std::endl; #endif it->handled[i] = true; check_detailed(meta_turns, *it, i, cycle++, it->index, for_operation, error); #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout <<" END CYCLE " << it->index << std::endl; #endif } } } } return error; } }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP detail/overlay/clip_linestring.hpp 0000644 00000021123 15125631657 0013377 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/strategies/cartesian/point_in_point.hpp> namespace boost { namespace geometry { namespace strategy { namespace intersection { /*! \brief Strategy: line clipping algorithm after Liang Barsky \ingroup overlay \details The Liang-Barsky line clipping algorithm clips a line with a clipping box. It is slightly adapted in the sense that it returns which points are clipped \tparam B input box type of clipping box \tparam P input/output point-type of segments to be clipped \note The algorithm is currently only implemented for 2D Cartesian points \note Though it is implemented in namespace strategy, and theoretically another strategy could be used, it is not (yet) updated to the general strategy concepts, and not (yet) splitted into a file in folder strategies \author Barend Gehrels, and the following recourses - A tutorial: http://www.skytopia.com/project/articles/compsci/clipping.html - a German applet (link broken): http://ls7-www.cs.uni-dortmund.de/students/projectgroups/acit/lineclip.shtml */ template<typename Box, typename Point> class liang_barsky { private: typedef model::referring_segment<Point> segment_type; template <typename CoordinateType, typename CalcType> inline bool check_edge(CoordinateType const& p, CoordinateType const& q, CalcType& t1, CalcType& t2) const { bool visible = true; if(p < 0) { CalcType const r = static_cast<CalcType>(q) / p; if (r > t2) visible = false; else if (r > t1) t1 = r; } else if(p > 0) { CalcType const r = static_cast<CalcType>(q) / p; if (r < t1) visible = false; else if (r < t2) t2 = r; } else { if (q < 0) visible = false; } return visible; } public: // TODO: Temporary, this strategy should be moved, it is cartesian-only typedef strategy::within::cartesian_point_point equals_point_point_strategy_type; static inline equals_point_point_strategy_type get_equals_point_point_strategy() { return equals_point_point_strategy_type(); } inline bool clip_segment(Box const& b, segment_type& s, bool& sp1_clipped, bool& sp2_clipped) const { typedef typename select_coordinate_type<Box, Point>::type coordinate_type; typedef typename select_most_precise<coordinate_type, double>::type calc_type; calc_type t1 = 0; calc_type t2 = 1; coordinate_type const dx = get<1, 0>(s) - get<0, 0>(s); coordinate_type const dy = get<1, 1>(s) - get<0, 1>(s); coordinate_type const p1 = -dx; coordinate_type const p2 = dx; coordinate_type const p3 = -dy; coordinate_type const p4 = dy; coordinate_type const q1 = get<0, 0>(s) - get<min_corner, 0>(b); coordinate_type const q2 = get<max_corner, 0>(b) - get<0, 0>(s); coordinate_type const q3 = get<0, 1>(s) - get<min_corner, 1>(b); coordinate_type const q4 = get<max_corner, 1>(b) - get<0, 1>(s); if (check_edge(p1, q1, t1, t2) // left && check_edge(p2, q2, t1, t2) // right && check_edge(p3, q3, t1, t2) // bottom && check_edge(p4, q4, t1, t2)) // top { sp1_clipped = t1 > 0; sp2_clipped = t2 < 1; if (sp2_clipped) { set<1, 0>(s, get<0, 0>(s) + t2 * dx); set<1, 1>(s, get<0, 1>(s) + t2 * dy); } if(sp1_clipped) { set<0, 0>(s, get<0, 0>(s) + t1 * dx); set<0, 1>(s, get<0, 1>(s) + t1 * dy); } return true; } return false; } template<typename Linestring, typename OutputIterator> inline void apply(Linestring& line_out, OutputIterator out) const { if (!boost::empty(line_out)) { *out = line_out; ++out; geometry::clear(line_out); } } }; }} // namespace strategy::intersection #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { /*! \brief Clips a linestring with a box \details A linestring is intersected (clipped) by the specified box and the resulting linestring, or pieces of linestrings, are sent to the specified output operator. \tparam OutputLinestring type of the output linestrings \tparam OutputIterator an output iterator which outputs linestrings \tparam Linestring linestring-type, for example a vector of points, matching the output-iterator type, the points should also match the input-iterator type \tparam Box box type \tparam Strategy strategy, a clipping strategy which should implement the methods "clip_segment" and "apply" */ template < typename OutputLinestring, typename OutputIterator, typename Range, typename RobustPolicy, typename Box, typename Strategy > OutputIterator clip_range_with_box(Box const& b, Range const& range, RobustPolicy const&, OutputIterator out, Strategy const& strategy) { if (boost::begin(range) == boost::end(range)) { return out; } typedef typename point_type<OutputLinestring>::type point_type; OutputLinestring line_out; typedef typename boost::range_iterator<Range const>::type iterator_type; iterator_type vertex = boost::begin(range); for(iterator_type previous = vertex++; vertex != boost::end(range); ++previous, ++vertex) { point_type p1, p2; geometry::convert(*previous, p1); geometry::convert(*vertex, p2); // Clip the segment. Five situations: // 1. Segment is invisible, finish line if any (shouldn't occur) // 2. Segment is completely visible. Add (p1)-p2 to line // 3. Point 1 is invisible (clipped), point 2 is visible. Start new line from p1-p2... // 4. Point 1 is visible, point 2 is invisible (clipped). End the line with ...p2 // 5. Point 1 and point 2 are both invisible (clipped). Start/finish an independant line p1-p2 // // This results in: // a. if p1 is clipped, start new line // b. if segment is partly or completely visible, add the segment // c. if p2 is clipped, end the line bool c1 = false; bool c2 = false; model::referring_segment<point_type> s(p1, p2); if (!strategy.clip_segment(b, s, c1, c2)) { strategy.apply(line_out, out); } else { // a. If necessary, finish the line and add a start a new one if (c1) { strategy.apply(line_out, out); } // b. Add p1 only if it is the first point, then add p2 if (boost::empty(line_out)) { detail::overlay::append_with_duplicates(line_out, p1); } detail::overlay::append_no_duplicates(line_out, p2, strategy.get_equals_point_point_strategy()); // c. If c2 is clipped, finish the line if (c2) { strategy.apply(line_out, out); } } } // Add last part strategy.apply(line_out, out); return out; } }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP detail/overlay/traverse.hpp 0000644 00000006270 15125631657 0012053 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP #include <cstddef> #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { /*! \brief Traverses through intersection points / geometries \ingroup overlay */ template < bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, overlay_type OverlayType, typename Backtrack = backtrack_check_self_intersections<Geometry1, Geometry2> > class traverse { template <typename Turns> static void reset_visits(Turns& turns) { for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { for (int i = 0; i < 2; i++) { it->operations[i].visited.reset(); } } } public : template < typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename Rings, typename TurnInfoMap, typename Clusters, typename Visitor > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, Rings& rings, TurnInfoMap& turn_info_map, Clusters& clusters, Visitor& visitor) { traversal_switch_detector < Reverse1, Reverse2, OverlayType, Geometry1, Geometry2, Turns, Clusters, RobustPolicy, Visitor > switch_detector(geometry1, geometry2, turns, clusters, robust_policy, visitor); switch_detector.iterate(); reset_visits(turns); traversal_ring_creator < Reverse1, Reverse2, OverlayType, Geometry1, Geometry2, Turns, TurnInfoMap, Clusters, IntersectionStrategy, RobustPolicy, Visitor, Backtrack > trav(geometry1, geometry2, turns, turn_info_map, clusters, intersection_strategy, robust_policy, visitor); std::size_t finalized_ring_size = boost::size(rings); typename Backtrack::state_type state; trav.iterate(rings, finalized_ring_size, state); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP detail/overlay/traversal_switch_detector.hpp 0000644 00000054207 15125631657 0015500 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2016 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018-2020. // Modifications copyright (c) 2018-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP #include <cstddef> #include <map> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Geometry1, typename Geometry2, typename Turns, typename Clusters, typename RobustPolicy, typename Visitor > struct traversal_switch_detector { static const operation_type target_operation = operation_from_overlay<OverlayType>::value; static const operation_type opposite_operation = target_operation == operation_union ? operation_intersection : operation_union; enum isolation_type { isolation_unknown = -1, isolation_no = 0, isolation_yes = 1, isolation_multiple = 2 }; typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; typedef std::set<signed_size_type> set_type; // Per ring, first turns are collected (in turn_indices), and later // a region_id is assigned struct merged_ring_properties { signed_size_type region_id; set_type turn_indices; merged_ring_properties() : region_id(-1) {} }; struct connection_properties { std::size_t count; // Contains turn-index OR, if clustered, minus-cluster_id set_type unique_turn_ids; connection_properties() : count(0) {} }; typedef std::map<signed_size_type, connection_properties> connection_map; // Per region, a set of properties is maintained, including its connections // to other regions struct region_properties { signed_size_type region_id; isolation_type isolated; set_type unique_turn_ids; // Maps from connected region_id to their properties connection_map connected_region_counts; region_properties() : region_id(-1) , isolated(isolation_unknown) {} }; // Keeps turn indices per ring typedef std::map<ring_identifier, merged_ring_properties > merge_map; typedef std::map<signed_size_type, region_properties> region_connection_map; typedef set_type::const_iterator set_iterator; inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, Clusters& clusters, RobustPolicy const& robust_policy, Visitor& visitor) : m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) , m_clusters(clusters) , m_robust_policy(robust_policy) , m_visitor(visitor) { } bool one_connection_to_another_region(region_properties const& region) const { // For example: // +----------------------+ // | __ | // | / \| // | | x // | \__/| // | | // +----------------------+ if (region.connected_region_counts.size() == 1) { connection_properties const& cprop = region.connected_region_counts.begin()->second; return cprop.count <= 1; } return region.connected_region_counts.empty(); } // TODO: might be combined with previous bool multiple_connections_to_one_region(region_properties const& region) const { // For example: // +----------------------+ // | __ | // | / \| // | | x // | \ /| // | / \| // | | x // | \__/| // | | // +----------------------+ if (region.connected_region_counts.size() == 1) { connection_properties const& cprop = region.connected_region_counts.begin()->second; return cprop.count > 1; } return false; } bool one_connection_to_multiple_regions(region_properties const& region) const { // For example: // +----------------------+ // | __ | __ // | / \|/ | // | | x | // | \__/|\__| // | | // +----------------------+ bool first = true; signed_size_type first_turn_id = 0; for (typename connection_map::const_iterator it = region.connected_region_counts.begin(); it != region.connected_region_counts.end(); ++it) { connection_properties const& cprop = it->second; if (cprop.count != 1) { return false; } signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin(); if (first) { first_turn_id = unique_turn_id; first = false; } else if (first_turn_id != unique_turn_id) { return false; } } return true; } bool ii_turn_connects_two_regions(region_properties const& region, region_properties const& connected_region, signed_size_type turn_index) const { turn_type const& turn = m_turns[turn_index]; if (! turn.both(operation_intersection)) { return false; } signed_size_type const id0 = turn.operations[0].enriched.region_id; signed_size_type const id1 = turn.operations[1].enriched.region_id; return (id0 == region.region_id && id1 == connected_region.region_id) || (id1 == region.region_id && id0 == connected_region.region_id); } bool isolated_multiple_connection(region_properties const& region, region_properties const& connected_region) const { if (connected_region.isolated != isolation_multiple) { return false; } // First step: compare turns of regions with turns of connected region set_type turn_ids = region.unique_turn_ids; for (set_iterator sit = connected_region.unique_turn_ids.begin(); sit != connected_region.unique_turn_ids.end(); ++sit) { turn_ids.erase(*sit); } // There should be one connection (turn or cluster) left if (turn_ids.size() != 1) { return false; } for (set_iterator sit = connected_region.unique_turn_ids.begin(); sit != connected_region.unique_turn_ids.end(); ++sit) { signed_size_type const id_or_index = *sit; if (id_or_index >= 0) { if (! ii_turn_connects_two_regions(region, connected_region, id_or_index)) { return false; } } else { signed_size_type const cluster_id = -id_or_index; typename Clusters::const_iterator it = m_clusters.find(cluster_id); if (it != m_clusters.end()) { cluster_info const& cinfo = it->second; for (set_iterator cit = cinfo.turn_indices.begin(); cit != cinfo.turn_indices.end(); ++cit) { if (! ii_turn_connects_two_regions(region, connected_region, *cit)) { return false; } } } } } return true; } bool has_only_isolated_children(region_properties const& region) const { bool first_with_turn = true; signed_size_type first_turn_id = 0; for (typename connection_map::const_iterator it = region.connected_region_counts.begin(); it != region.connected_region_counts.end(); ++it) { signed_size_type const region_id = it->first; connection_properties const& cprop = it->second; typename region_connection_map::const_iterator mit = m_connected_regions.find(region_id); if (mit == m_connected_regions.end()) { // Should not occur return false; } region_properties const& connected_region = mit->second; if (cprop.count != 1) { // If there are more connections, check their isolation if (! isolated_multiple_connection(region, connected_region)) { return false; } } if (connected_region.isolated != isolation_yes && connected_region.isolated != isolation_multiple) { signed_size_type const unique_turn_id = *cprop.unique_turn_ids.begin(); if (first_with_turn) { first_turn_id = unique_turn_id; first_with_turn = false; } else if (first_turn_id != unique_turn_id) { return false; } } } // If there is only one connection (with a 'parent'), and all other // connections are itself isolated, it is isolated return true; } void get_isolated_regions() { typedef typename region_connection_map::iterator it_type; // First time: check regions isolated (one connection only), // semi-isolated (multiple connections between same region), // and complex isolated (connection with multiple rings but all // at same point) for (it_type it = m_connected_regions.begin(); it != m_connected_regions.end(); ++it) { region_properties& properties = it->second; if (one_connection_to_another_region(properties)) { properties.isolated = isolation_yes; } else if (multiple_connections_to_one_region(properties)) { properties.isolated = isolation_multiple; } else if (one_connection_to_multiple_regions(properties)) { properties.isolated = isolation_yes; } } // Propagate isolation to next level // TODO: should be optimized std::size_t defensive_check = 0; bool changed = true; while (changed && defensive_check++ < m_connected_regions.size()) { changed = false; for (it_type it = m_connected_regions.begin(); it != m_connected_regions.end(); ++it) { region_properties& properties = it->second; if (properties.isolated == isolation_unknown && has_only_isolated_children(properties)) { properties.isolated = isolation_yes; changed = true; } } } } void assign_isolation() { for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { turn_type& turn = m_turns[turn_index]; for (int op_index = 0; op_index < 2; op_index++) { turn_operation_type& op = turn.operations[op_index]; typename region_connection_map::const_iterator mit = m_connected_regions.find(op.enriched.region_id); if (mit != m_connected_regions.end()) { region_properties const& prop = mit->second; op.enriched.isolated = prop.isolated == isolation_yes; } } } } void assign_region_ids() { for (typename merge_map::const_iterator it = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it) { ring_identifier const& ring_id = it->first; merged_ring_properties const& properties = it->second; for (set_iterator sit = properties.turn_indices.begin(); sit != properties.turn_indices.end(); ++sit) { turn_type& turn = m_turns[*sit]; if (! acceptable(turn)) { // No assignment necessary continue; } for (int i = 0; i < 2; i++) { turn_operation_type& op = turn.operations[i]; if (ring_id_by_seg_id(op.seg_id) == ring_id) { op.enriched.region_id = properties.region_id; } } } } } void assign_connected_regions() { for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { turn_type const& turn = m_turns[turn_index]; signed_size_type const unique_turn_id = turn.is_clustered() ? -turn.cluster_id : turn_index; turn_operation_type op0 = turn.operations[0]; turn_operation_type op1 = turn.operations[1]; signed_size_type const& id0 = op0.enriched.region_id; signed_size_type const& id1 = op1.enriched.region_id; // Add region (by assigning) and add involved turns if (id0 != -1) { m_connected_regions[id0].region_id = id0; m_connected_regions[id0].unique_turn_ids.insert(unique_turn_id); } if (id1 != -1 && id0 != id1) { m_connected_regions[id1].region_id = id1; m_connected_regions[id1].unique_turn_ids.insert(unique_turn_id); } if (id0 != id1 && id0 != -1 && id1 != -1) { // Assign connections connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1]; connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0]; // Reference this turn or cluster to later check uniqueness on ring if (prop0.unique_turn_ids.count(unique_turn_id) == 0) { prop0.count++; prop0.unique_turn_ids.insert(unique_turn_id); } if (prop1.unique_turn_ids.count(unique_turn_id) == 0) { prop1.count++; prop1.unique_turn_ids.insert(unique_turn_id); } } } } inline bool acceptable(turn_type const& turn) const { // Discarded turns don't connect rings to the same region // Also xx are not relevant // (otherwise discarded colocated uu turn could make a connection) return ! turn.discarded && ! turn.both(operation_blocked); } inline bool connects_same_region(turn_type const& turn) const { if (! acceptable(turn)) { return false; } if (! turn.is_clustered()) { // If it is a uu/ii-turn (non clustered), it is never same region return ! (turn.both(operation_union) || turn.both(operation_intersection)); } if (BOOST_GEOMETRY_CONDITION(target_operation == operation_union)) { // It is a cluster, check zones // (assigned by sort_by_side/handle colocations) of both operations return turn.operations[0].enriched.zone == turn.operations[1].enriched.zone; } // For an intersection, two regions connect if they are not ii // (ii-regions are isolated) or, in some cases, not iu (for example // when a multi-polygon is inside an interior ring and connecting it) return ! (turn.both(operation_intersection) || turn.combination(operation_intersection, operation_union)); } inline signed_size_type get_region_id(turn_operation_type const& op) const { return op.enriched.region_id; } void create_region(signed_size_type& new_region_id, ring_identifier const& ring_id, merged_ring_properties& properties, signed_size_type region_id = -1) { if (properties.region_id > 0) { // Already handled return; } // Assign new id if this is a new region if (region_id == -1) { region_id = new_region_id++; } // Assign this ring to specified region properties.region_id = region_id; #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl; #endif // Find connecting rings, recursively for (set_iterator sit = properties.turn_indices.begin(); sit != properties.turn_indices.end(); ++sit) { signed_size_type const turn_index = *sit; turn_type const& turn = m_turns[turn_index]; if (! connects_same_region(turn)) { // This is a non clustered uu/ii-turn, or a cluster connecting different 'zones' continue; } // Union: This turn connects two rings (interior connected), create the region // Intersection: This turn connects two rings, set same regions for these two rings for (int op_index = 0; op_index < 2; op_index++) { turn_operation_type const& op = turn.operations[op_index]; ring_identifier connected_ring_id = ring_id_by_seg_id(op.seg_id); if (connected_ring_id != ring_id) { propagate_region(new_region_id, connected_ring_id, region_id); } } } } void propagate_region(signed_size_type& new_region_id, ring_identifier const& ring_id, signed_size_type region_id) { typename merge_map::iterator it = m_turns_per_ring.find(ring_id); if (it != m_turns_per_ring.end()) { create_region(new_region_id, ring_id, it->second, region_id); } } void iterate() { #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) std::cout << "BEGIN ITERATION GETTING REGION_IDS" << std::endl; #endif // Collect turns per ring m_turns_per_ring.clear(); m_connected_regions.clear(); for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { turn_type const& turn = m_turns[turn_index]; if (turn.discarded && BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)) { // Discarded turn (union currently still needs it to determine regions) continue; } for (int op_index = 0; op_index < 2; op_index++) { turn_operation_type const& op = turn.operations[op_index]; m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].turn_indices.insert(turn_index); } } // All rings having turns are in turns/ring map. Process them. { signed_size_type new_region_id = 1; for (typename merge_map::iterator it = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it) { create_region(new_region_id, it->first, it->second); } assign_region_ids(); assign_connected_regions(); get_isolated_regions(); assign_isolation(); } #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) std::cout << "END ITERATION GETTIN REGION_IDS" << std::endl; for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { turn_type const& turn = m_turns[turn_index]; if ((turn.both(operation_union) || turn.both(operation_intersection)) && ! turn.is_clustered()) { std::cout << "UU/II RESULT " << turn_index << " -> " << turn.operations[0].enriched.region_id << " " << turn.operations[1].enriched.region_id << std::endl; } } for (typename Clusters::const_iterator it = m_clusters.begin(); it != m_clusters.end(); ++it) { cluster_info const& cinfo = it->second; std::cout << "CL RESULT " << it->first << " -> " << cinfo.open_count << std::endl; } #endif } private: Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; Turns& m_turns; Clusters& m_clusters; merge_map m_turns_per_ring; region_connection_map m_connected_regions; RobustPolicy const& m_robust_policy; Visitor& m_visitor; }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_SWITCH_DETECTOR_HPP detail/overlay/get_distance_measure.hpp 0000644 00000010652 15125631657 0014371 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_DISTANCE_MEASURE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_DISTANCE_MEASURE_HPP #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_system.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/arithmetic/infinite_line_functions.hpp> #include <boost/geometry/algorithms/detail/make/make.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> #include <cmath> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename T> struct distance_measure { T measure; distance_measure() : measure(T()) {} // Returns true if the distance measure is small. // This is an arbitrary boundary, to enable some behaviour // (for example include or exclude turns), which are checked later // with other conditions. bool is_small() const { return geometry::math::abs(measure) < 1.0e-3; } // Returns true if the distance measure is absolutely zero bool is_zero() const { return ! is_positive() && ! is_negative(); } // Returns true if the distance measure is positive. Distance measure // algorithm returns positive value if it is located on the left side. bool is_positive() const { return measure > T(0); } // Returns true if the distance measure is negative. Distance measure // algorithm returns negative value if it is located on the right side. bool is_negative() const { return measure < T(0); } }; } // detail namespace detail_dispatch { // TODO: this is effectively a strategy, but for internal usage. // It might be moved to the strategies folder. template <typename CalculationType, typename CsTag> struct get_distance_measure : not_implemented<CsTag> {}; template <typename CalculationType> struct get_distance_measure<CalculationType, cartesian_tag> { typedef detail::distance_measure<CalculationType> result_type; template <typename SegmentPoint, typename Point> static result_type apply(SegmentPoint const& p1, SegmentPoint const& p2, Point const& p) { // Get the distance measure / side value // It is not a real distance and purpose is // to detect small differences in collinearity typedef model::infinite_line<CalculationType> line_type; line_type const line = detail::make::make_infinite_line<CalculationType>(p1, p2); result_type result; result.measure = arithmetic::side_value(line, p); return result; } }; template <typename CalculationType> struct get_distance_measure<CalculationType, spherical_tag> { typedef detail::distance_measure<CalculationType> result_type; template <typename SegmentPoint, typename Point> static result_type apply(SegmentPoint const& , SegmentPoint const& , Point const& ) { // TODO, optional result_type result; return result; } }; template <typename CalculationType> struct get_distance_measure<CalculationType, geographic_tag> : get_distance_measure<CalculationType, spherical_tag> {}; } // namespace detail_dispatch namespace detail { // Returns a (often very tiny) value to indicate its side, and distance, // 0 (absolutely 0, not even an epsilon) means collinear. Like side, // a negative means that p is to the right of p1-p2. And a positive value // means that p is to the left of p1-p2. template <typename SegmentPoint, typename Point> static distance_measure<typename select_coordinate_type<SegmentPoint, Point>::type> get_distance_measure(SegmentPoint const& p1, SegmentPoint const& p2, Point const& p) { typedef typename geometry::cs_tag<Point>::type cs_tag; return detail_dispatch::get_distance_measure < typename select_coordinate_type<SegmentPoint, Point>::type, cs_tag >::apply(p1, p2, p); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_DISTANCE_MEASURE_HPP detail/overlay/is_self_turn.hpp 0000644 00000003113 15125631657 0012705 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017-2017 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <overlay_type OverlayType> struct is_self_turn_check { template <typename Turn> static inline bool apply(Turn const& turn) { return turn.operations[0].seg_id.source_index == turn.operations[1].seg_id.source_index; } }; template <> struct is_self_turn_check<overlay_buffer> { template <typename Turn> static inline bool apply(Turn const& /*turn*/) { return false; } }; template <> struct is_self_turn_check<overlay_dissolve> { template <typename Turn> static inline bool apply(Turn const& /*turn*/) { return false; } }; template <overlay_type OverlayType, typename Turn> bool is_self_turn(Turn const& turn) { return is_self_turn_check<OverlayType>::apply(turn); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP detail/overlay/add_rings.hpp 0000644 00000013641 15125631657 0012152 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/throw_exception.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exception.hpp> #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/detail/overlay/convert_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < typename GeometryOut, typename Geometry1, typename Geometry2, typename RingCollection > inline void convert_and_add(GeometryOut& result, Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection, ring_identifier id, bool reversed, bool append) { typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; typedef typename geometry::tag<GeometryOut>::type tag_out; if (id.source_index == 0) { convert_ring<tag_out>::apply(result, get_ring<tag1>::apply(id, geometry1), append, reversed); } else if (id.source_index == 1) { convert_ring<tag_out>::apply(result, get_ring<tag2>::apply(id, geometry2), append, reversed); } else if (id.source_index == 2) { convert_ring<tag_out>::apply(result, get_ring<void>::apply(id, collection), append, reversed); } } enum add_rings_error_handling { add_rings_ignore_unordered, add_rings_add_unordered, add_rings_throw_if_reversed }; template < typename GeometryOut, typename SelectionMap, typename Geometry1, typename Geometry2, typename RingCollection, typename OutputIterator, typename AreaStrategy > inline OutputIterator add_rings(SelectionMap const& map, Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection, OutputIterator out, AreaStrategy const& area_strategy, add_rings_error_handling error_handling = add_rings_ignore_unordered) { typedef typename SelectionMap::const_iterator iterator; typedef typename AreaStrategy::template result_type < GeometryOut >::type area_type; area_type const zero = 0; std::size_t const min_num_points = core_detail::closure::minimum_ring_size < geometry::closure < typename boost::range_value < RingCollection const >::type >::value >::value; for (iterator it = boost::begin(map); it != boost::end(map); ++it) { if (! it->second.discarded && it->second.parent.source_index == -1) { GeometryOut result; convert_and_add(result, geometry1, geometry2, collection, it->first, it->second.reversed, false); // Add children for (typename std::vector<ring_identifier>::const_iterator child_it = it->second.children.begin(); child_it != it->second.children.end(); ++child_it) { iterator mit = map.find(*child_it); if (mit != map.end() && ! mit->second.discarded) { convert_and_add(result, geometry1, geometry2, collection, *child_it, mit->second.reversed, true); } } // Only add rings if they satisfy minimal requirements. // This cannot be done earlier (during traversal), not // everything is figured out yet (sum of positive/negative rings) if (geometry::num_points(result) >= min_num_points) { area_type const area = geometry::area(result, area_strategy); // Ignore if area is 0 if (! math::equals(area, zero)) { if (error_handling == add_rings_add_unordered || area > zero) { *out++ = result; } else if (error_handling == add_rings_throw_if_reversed) { BOOST_THROW_EXCEPTION(invalid_output_exception()); } } } } } return out; } template < typename GeometryOut, typename SelectionMap, typename Geometry, typename RingCollection, typename OutputIterator, typename AreaStrategy > inline OutputIterator add_rings(SelectionMap const& map, Geometry const& geometry, RingCollection const& collection, OutputIterator out, AreaStrategy const& area_strategy) { Geometry empty; return add_rings<GeometryOut>(map, geometry, empty, collection, out, area_strategy); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP detail/overlay/follow.hpp 0000644 00000041322 15125631657 0011517 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP #include <cstddef> #include <type_traits> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/relate/turns.hpp> #include <boost/geometry/algorithms/detail/tupled_output.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { namespace following { template <typename Turn, typename Operation> inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op) { // (Blocked means: blocked for polygon/polygon intersection, because // they are reversed. But for polygon/line it is similar to continue) return op.operation == operation_intersection || op.operation == operation_continue || op.operation == operation_blocked ; } template < typename Turn, typename Operation, typename LineString, typename Polygon, typename PtInPolyStrategy > inline bool last_covered_by(Turn const& /*turn*/, Operation const& op, LineString const& linestring, Polygon const& polygon, PtInPolyStrategy const& strategy) { return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy); } template < typename Turn, typename Operation, typename LineString, typename Polygon, typename PtInPolyStrategy > inline bool is_leaving(Turn const& turn, Operation const& op, bool entered, bool first, LineString const& linestring, Polygon const& polygon, PtInPolyStrategy const& strategy) { if (op.operation == operation_union) { return entered || turn.method == method_crosses || (first && op.position != position_front && last_covered_by(turn, op, linestring, polygon, strategy)) ; } return false; } template < typename Turn, typename Operation, typename LineString, typename Polygon, typename PtInPolyStrategy > inline bool is_staying_inside(Turn const& turn, Operation const& op, bool entered, bool first, LineString const& linestring, Polygon const& polygon, PtInPolyStrategy const& strategy) { if (turn.method == method_crosses) { // The normal case, this is completely covered with entering/leaving // so stay out of this time consuming "covered_by" return false; } if (is_entering(turn, op)) { return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy)); } return false; } template < typename Turn, typename Operation, typename Linestring, typename Polygon, typename PtInPolyStrategy > inline bool was_entered(Turn const& turn, Operation const& op, bool first, Linestring const& linestring, Polygon const& polygon, PtInPolyStrategy const& strategy) { if (first && (turn.method == method_collinear || turn.method == method_equal)) { return last_covered_by(turn, op, linestring, polygon, strategy); } return false; } template < typename Turn, typename Operation > inline bool is_touching(Turn const& turn, Operation const& op, bool entered) { return (op.operation == operation_union || op.operation == operation_blocked) && (turn.method == method_touch || turn.method == method_touch_interior) && !entered && !op.is_collinear; } template < typename GeometryOut, typename Tag = typename geometry::tag<GeometryOut>::type > struct add_isolated_point {}; template <typename LineStringOut> struct add_isolated_point<LineStringOut, linestring_tag> { template <typename Point, typename OutputIterator> static inline void apply(Point const& point, OutputIterator& out) { LineStringOut isolated_point_ls; geometry::append(isolated_point_ls, point); #ifndef BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS geometry::append(isolated_point_ls, point); #endif // BOOST_GEOMETRY_ALLOW_ONE_POINT_LINESTRINGS *out++ = isolated_point_ls; } }; template <typename PointOut> struct add_isolated_point<PointOut, point_tag> { template <typename Point, typename OutputIterator> static inline void apply(Point const& point, OutputIterator& out) { PointOut isolated_point; geometry::detail::conversion::convert_point_to_point(point, isolated_point); *out++ = isolated_point; } }; // Template specialization structure to call the right actions for the right type template <overlay_type OverlayType, bool RemoveSpikes = true> struct action_selector { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "If you get here the overlay type is not intersection or difference.", std::integral_constant<overlay_type, OverlayType>); }; // Specialization for intersection, containing the implementation template <bool RemoveSpikes> struct action_selector<overlay_intersection, RemoveSpikes> { template < typename OutputIterator, typename LineStringOut, typename LineString, typename Point, typename Operation, typename Strategy, typename RobustPolicy > static inline void enter(LineStringOut& current_piece, LineString const& , segment_identifier& segment_id, signed_size_type , Point const& point, Operation const& operation, Strategy const& strategy, RobustPolicy const& , OutputIterator& ) { // On enter, append the intersection point and remember starting point // TODO: we don't check on spikes for linestrings (?). Consider this. detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy()); segment_id = operation.seg_id; } template < typename OutputIterator, typename LineStringOut, typename LineString, typename Point, typename Operation, typename Strategy, typename RobustPolicy > static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& , Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { // On leave, copy all segments from starting point, append the intersection point // and add the output piece detail::copy_segments::copy_segments_linestring < false, RemoveSpikes >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece); detail::overlay::append_no_duplicates(current_piece, point, strategy.get_equals_point_point_strategy()); if (::boost::size(current_piece) > 1) { *out++ = current_piece; } geometry::clear(current_piece); } template < typename LineStringOrPointOut, typename Point, typename OutputIterator > static inline void isolated_point(Point const& point, OutputIterator& out) { add_isolated_point<LineStringOrPointOut>::apply(point, out); } static inline bool is_entered(bool entered) { return entered; } static inline bool included(int inside_value) { return inside_value >= 0; // covered_by } }; // Specialization for difference, which reverses these actions template <bool RemoveSpikes> struct action_selector<overlay_difference, RemoveSpikes> { typedef action_selector<overlay_intersection, RemoveSpikes> normal_action; template < typename OutputIterator, typename LineStringOut, typename LineString, typename Point, typename Operation, typename Strategy, typename RobustPolicy > static inline void enter(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& operation, Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { normal_action::leave(current_piece, linestring, segment_id, index, point, operation, strategy, robust_policy, out); } template < typename OutputIterator, typename LineStringOut, typename LineString, typename Point, typename Operation, typename Strategy, typename RobustPolicy > static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& operation, Strategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { normal_action::enter(current_piece, linestring, segment_id, index, point, operation, strategy, robust_policy, out); } template < typename LineStringOrPointOut, typename Point, typename OutputIterator > static inline void isolated_point(Point const&, OutputIterator const&) { } static inline bool is_entered(bool entered) { return ! normal_action::is_entered(entered); } static inline bool included(int inside_value) { return ! normal_action::included(inside_value); } }; } // namespace following /*! \brief Follows a linestring from intersection point to intersection point, outputting which is inside, or outside, a ring or polygon \ingroup overlay */ template < typename GeometryOut, typename LineString, typename Polygon, overlay_type OverlayType, bool RemoveSpikes, bool FollowIsolatedPoints > class follow { typedef geometry::detail::output_geometry_access < GeometryOut, linestring_tag, linestring_tag > linear; typedef geometry::detail::output_geometry_access < GeometryOut, point_tag, linestring_tag > pointlike; public : static inline bool included(int inside_value) { return following::action_selector < OverlayType, RemoveSpikes >::included(inside_value); } template < typename Turns, typename OutputIterator, typename RobustPolicy, typename Strategy > static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon, detail::overlay::operation_type , // TODO: this parameter might be redundant Turns& turns, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { typedef typename boost::range_iterator<Turns>::type turn_iterator; typedef typename boost::range_value<Turns>::type turn_type; typedef typename boost::range_iterator < typename turn_type::container_type >::type turn_operation_iterator_type; typedef following::action_selector<OverlayType, RemoveSpikes> action; typedef typename Strategy::cs_tag cs_tag; typename Strategy::template point_in_geometry_strategy < LineString, Polygon >::type const pt_in_poly_strategy = strategy.template get_point_in_geometry_strategy<LineString, Polygon>(); // Sort intersection points on segments-along-linestring, and distance // (like in enrich is done for poly/poly) // sort turns by Linear seg_id, then by fraction, then // for same ring id: x, u, i, c // for different ring id: c, i, u, x typedef relate::turns::less < 0, relate::turns::less_op_linear_areal_single<0>, cs_tag > turn_less; std::sort(boost::begin(turns), boost::end(turns), turn_less()); typename linear::type current_piece; geometry::segment_identifier current_segment_id(0, -1, -1, -1); // Iterate through all intersection points (they are ordered along the line) bool entered = false; bool first = true; for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it) { turn_operation_iterator_type iit = boost::begin(it->operations); if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy)) { debug_traverse(*it, *iit, "-> Was entered"); entered = true; } if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy)) { debug_traverse(*it, *iit, "-> Staying inside"); entered = true; } else if (following::is_entering(*it, *iit)) { debug_traverse(*it, *iit, "-> Entering"); entered = true; action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, strategy, robust_policy, linear::get(out)); } else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy)) { debug_traverse(*it, *iit, "-> Leaving"); entered = false; action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, strategy, robust_policy, linear::get(out)); } else if (BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints) && following::is_touching(*it, *iit, entered)) { debug_traverse(*it, *iit, "-> Isolated point"); action::template isolated_point < typename pointlike::type >(it->point, pointlike::get(out)); } first = false; } if (action::is_entered(entered)) { detail::copy_segments::copy_segments_linestring < false, RemoveSpikes >::apply(linestring, current_segment_id, static_cast<signed_size_type>(boost::size(linestring) - 1), strategy, robust_policy, current_piece); } // Output the last one, if applicable std::size_t current_piece_size = ::boost::size(current_piece); if (current_piece_size > 1) { *linear::get(out)++ = current_piece; } else if (BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints) && current_piece_size == 1) { action::template isolated_point < typename pointlike::type >(range::front(current_piece), pointlike::get(out)); } return out; } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP detail/overlay/pointlike_areal.hpp 0000644 00000023740 15125631657 0013363 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2020, 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_DETAIL_OVERLAY_POINTLIKE_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_AREAL_HPP #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/not.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/geometries/point.hpp> // TEMP #include <boost/geometry/strategies/envelope/cartesian.hpp> #include <boost/geometry/strategies/envelope/geographic.hpp> #include <boost/geometry/strategies/envelope/spherical.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // difference/intersection of multipoint-multipolygon template < typename MultiPoint, typename MultiPolygon, typename PointOut, overlay_type OverlayType, typename Policy > class multipoint_multipolygon_point { private: template <typename ExpandPointStrategy> struct expand_box_point { template <typename Box, typename Point> static inline void apply(Box& total, Point const& point) { geometry::expand(total, point, ExpandPointStrategy()); } }; template <typename ExpandBoxStrategy> struct expand_box_boxpair { template <typename Box1, typename Box2, typename SizeT> static inline void apply(Box1& total, std::pair<Box2, SizeT> const& box_pair) { geometry::expand(total, box_pair.first, ExpandBoxStrategy()); } }; template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { return ! geometry::disjoint(point, box, DisjointPointBoxStrategy()); } }; template <typename DisjointBoxBoxStrategy> struct overlaps_box_boxpair { template <typename Box1, typename Box2, typename SizeT> static inline bool apply(Box1 const& box, std::pair<Box2, SizeT> const& box_pair) { return ! geometry::disjoint(box, box_pair.first, DisjointBoxBoxStrategy()); } }; template <typename OutputIterator, typename Strategy> class item_visitor_type { public: item_visitor_type(MultiPolygon const& multipolygon, OutputIterator& oit, Strategy const& strategy) : m_multipolygon(multipolygon) , m_oit(oit) , m_strategy(strategy) {} template <typename Point, typename Box, typename SizeT> inline bool apply(Point const& item1, std::pair<Box, SizeT> const& item2) { action_selector_pl < PointOut, overlay_intersection >::apply(item1, Policy::apply(item1, range::at(m_multipolygon, item2.second), m_strategy), m_oit); return true; } private: MultiPolygon const& m_multipolygon; OutputIterator& m_oit; Strategy const& m_strategy; }; template <typename Iterator, typename Box, typename SizeT, typename EnvelopeStrategy> static inline void fill_box_pairs(Iterator first, Iterator last, std::vector<std::pair<Box, SizeT> > & box_pairs, EnvelopeStrategy const& strategy) { SizeT index = 0; for (; first != last; ++first, ++index) { box_pairs.push_back( std::make_pair(geometry::return_envelope<Box>(*first, strategy), index)); } } template <typename OutputIterator, typename Strategy> static inline OutputIterator get_common_points(MultiPoint const& multipoint, MultiPolygon const& multipolygon, OutputIterator oit, Strategy const& strategy) { item_visitor_type<OutputIterator, Strategy> item_visitor(multipolygon, oit, strategy); typedef geometry::model::point < typename geometry::coordinate_type<MultiPoint>::type, geometry::dimension<MultiPoint>::value, typename geometry::coordinate_system<MultiPoint>::type > point_type; typedef geometry::model::box<point_type> box_type; typedef std::pair<box_type, std::size_t> box_pair; std::vector<box_pair> box_pairs; box_pairs.reserve(boost::size(multipolygon)); fill_box_pairs(boost::begin(multipolygon), boost::end(multipolygon), box_pairs, strategy.get_envelope_strategy()); // TEMP - envelope umbrella strategy also contains // expand strategies using expand_box_strategy_type = decltype( strategies::envelope::services::strategy_converter < typename Strategy::envelope_strategy_type >::get(strategy.get_envelope_strategy()) .expand(std::declval<box_type>(), std::declval<box_type>())); typedef typename Strategy::disjoint_box_box_strategy_type disjoint_box_box_strategy_type; typedef typename Strategy::disjoint_point_box_strategy_type disjoint_point_box_strategy_type; typedef typename Strategy::expand_point_strategy_type expand_point_strategy_type; geometry::partition < box_type >::apply(multipoint, box_pairs, item_visitor, expand_box_point<expand_point_strategy_type>(), overlaps_box_point<disjoint_point_box_strategy_type>(), expand_box_boxpair<expand_box_strategy_type>(), overlaps_box_boxpair<disjoint_box_box_strategy_type>()); return oit; } public: template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(MultiPoint const& multipoint, MultiPolygon const& multipolygon, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { typedef std::vector < typename boost::range_value<MultiPoint>::type > point_vector_type; point_vector_type common_points; // compute the common points get_common_points(multipoint, multipolygon, std::back_inserter(common_points), strategy); return multipoint_multipoint_point < MultiPoint, point_vector_type, PointOut, OverlayType >::apply(multipoint, common_points, robust_policy, oit, strategy); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { namespace overlay { // dispatch struct for pointlike-areal difference/intersection computation template < typename PointLike, typename Areal, typename PointOut, overlay_type OverlayType, typename Tag1, typename Tag2 > struct pointlike_areal_point : not_implemented<PointLike, Areal, PointOut> {}; template < typename Point, typename Areal, typename PointOut, overlay_type OverlayType, typename Tag2 > struct pointlike_areal_point < Point, Areal, PointOut, OverlayType, point_tag, Tag2 > : detail::overlay::point_single_point < Point, Areal, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; // TODO: Consider implementing Areal-specific version // calculating envelope first in order to reject Points without // calling disjoint for Rings and Polygons template < typename MultiPoint, typename Areal, typename PointOut, overlay_type OverlayType, typename Tag2 > struct pointlike_areal_point < MultiPoint, Areal, PointOut, OverlayType, multi_point_tag, Tag2 > : detail::overlay::multipoint_single_point < MultiPoint, Areal, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; template < typename MultiPoint, typename MultiPolygon, typename PointOut, overlay_type OverlayType > struct pointlike_areal_point < MultiPoint, MultiPolygon, PointOut, OverlayType, multi_point_tag, multi_polygon_tag > : detail::overlay::multipoint_multipolygon_point < MultiPoint, MultiPolygon, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; }} // namespace detail_dispatch::overlay #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_AREAL_HPP detail/overlay/copy_segments.hpp 0000644 00000026324 15125631657 0013101 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP #include <type_traits> #include <vector> #include <boost/array.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp> #include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace copy_segments { template <bool Reverse> struct copy_segments_ring { template < typename Ring, typename SegmentIdentifier, typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(Ring const& ring, SegmentIdentifier const& seg_id, signed_size_type to_index, SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { typedef typename closeable_view < Ring const, closure<Ring>::value >::type cview_type; typedef typename reversible_view < cview_type const, Reverse ? iterate_reverse : iterate_forward >::type rview_type; typedef typename boost::range_iterator<rview_type const>::type iterator; typedef geometry::ever_circling_iterator<iterator> ec_iterator; cview_type cview(ring); rview_type view(cview); // The problem: sometimes we want to from "3" to "2" // -> end = "3" -> end == begin // This is not convenient with iterators. // So we use the ever-circling iterator and determine when to step out signed_size_type const from_index = seg_id.segment_index + 1; // Sanity check BOOST_GEOMETRY_ASSERT(from_index < static_cast<signed_size_type>(boost::size(view))); ec_iterator it(boost::begin(view), boost::end(view), boost::begin(view) + from_index); // [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK // [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK // [1..1], travel the whole ring round signed_size_type const count = from_index <= to_index ? to_index - from_index + 1 : static_cast<signed_size_type>(boost::size(view)) - from_index + to_index + 1; for (signed_size_type i = 0; i < count; ++i, ++it) { detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy); } } }; template <bool Reverse, bool RemoveSpikes = true> class copy_segments_linestring { private: // remove spikes template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy> static inline void append_to_output(RangeOut& current_output, Point const& point, SideStrategy const& strategy, RobustPolicy const& robust_policy, std::true_type const&) { detail::overlay::append_no_dups_or_spikes(current_output, point, strategy, robust_policy); } // keep spikes template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy> static inline void append_to_output(RangeOut& current_output, Point const& point, SideStrategy const& strategy, RobustPolicy const&, std::false_type const&) { detail::overlay::append_no_duplicates(current_output, point, strategy.get_equals_point_point_strategy()); } public: template < typename LineString, typename SegmentIdentifier, typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(LineString const& ls, SegmentIdentifier const& seg_id, signed_size_type to_index, SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { signed_size_type const from_index = seg_id.segment_index + 1; // Sanity check if ( from_index > to_index || from_index < 0 || to_index >= static_cast<signed_size_type>(boost::size(ls)) ) { return; } signed_size_type const count = to_index - from_index + 1; typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index; for (signed_size_type i = 0; i < count; ++i, ++it) { append_to_output(current_output, *it, strategy, robust_policy, std::integral_constant<bool, RemoveSpikes>()); } } }; template <bool Reverse> struct copy_segments_polygon { template < typename Polygon, typename SegmentIdentifier, typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(Polygon const& polygon, SegmentIdentifier const& seg_id, signed_size_type to_index, SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { // Call ring-version with the right ring copy_segments_ring<Reverse>::apply ( seg_id.ring_index < 0 ? geometry::exterior_ring(polygon) : range::at(geometry::interior_rings(polygon), seg_id.ring_index), seg_id, to_index, strategy, robust_policy, current_output ); } }; template <bool Reverse> struct copy_segments_box { template < typename Box, typename SegmentIdentifier, typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(Box const& box, SegmentIdentifier const& seg_id, signed_size_type to_index, SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { signed_size_type index = seg_id.segment_index + 1; BOOST_GEOMETRY_ASSERT(index < 5); signed_size_type const count = index <= to_index ? to_index - index + 1 : 5 - index + to_index + 1; // Create array of points, the fifth one closes it boost::array<typename point_type<Box>::type, 5> bp; assign_box_corners_oriented<Reverse>(box, bp); bp[4] = bp[0]; // (possibly cyclic) copy to output // (see comments in ring-version) for (signed_size_type i = 0; i < count; i++, index++) { detail::overlay::append_no_dups_or_spikes(current_output, bp[index % 5], strategy, robust_policy); } } }; template<typename Policy> struct copy_segments_multi { template < typename MultiGeometry, typename SegmentIdentifier, typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(MultiGeometry const& multi_geometry, SegmentIdentifier const& seg_id, signed_size_type to_index, SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { BOOST_GEOMETRY_ASSERT ( seg_id.multi_index >= 0 && static_cast<std::size_t>(seg_id.multi_index) < boost::size(multi_geometry) ); // Call the single-version Policy::apply(range::at(multi_geometry, seg_id.multi_index), seg_id, to_index, strategy, robust_policy, current_output); } }; }} // namespace detail::copy_segments #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Tag, bool Reverse > struct copy_segments : not_implemented<Tag> {}; template <bool Reverse> struct copy_segments<ring_tag, Reverse> : detail::copy_segments::copy_segments_ring<Reverse> {}; template <bool Reverse> struct copy_segments<linestring_tag, Reverse> : detail::copy_segments::copy_segments_linestring<Reverse> {}; template <bool Reverse> struct copy_segments<polygon_tag, Reverse> : detail::copy_segments::copy_segments_polygon<Reverse> {}; template <bool Reverse> struct copy_segments<box_tag, Reverse> : detail::copy_segments::copy_segments_box<Reverse> {}; template<bool Reverse> struct copy_segments<multi_polygon_tag, Reverse> : detail::copy_segments::copy_segments_multi < detail::copy_segments::copy_segments_polygon<Reverse> > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief Copy segments from a geometry, starting with the specified segment (seg_id) until the specified index (to_index) \ingroup overlay */ template < bool Reverse, typename Geometry, typename SegmentIdentifier, typename SideStrategy, typename RobustPolicy, typename RangeOut > inline void copy_segments(Geometry const& geometry, SegmentIdentifier const& seg_id, signed_size_type to_index, SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& range_out) { concepts::check<Geometry const>(); dispatch::copy_segments < typename tag<Geometry>::type, Reverse >::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP detail/overlay/append_no_dups_or_spikes.hpp 0000644 00000016537 15125631657 0015303 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP #include <type_traits> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/static_assert.hpp> #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // TODO: move this / rename this template <typename Point1, typename Point2, typename EqualsStrategy, typename RobustPolicy> inline bool points_equal_or_close(Point1 const& point1, Point2 const& point2, EqualsStrategy const& strategy, RobustPolicy const& robust_policy) { if (detail::equals::equals_point_point(point1, point2, strategy)) { return true; } if (BOOST_GEOMETRY_CONDITION(! RobustPolicy::enabled)) { return false; } // Try using specified robust policy typedef typename geometry::robust_point_type < Point1, RobustPolicy >::type robust_point_type; robust_point_type point1_rob, point2_rob; geometry::recalculate(point1_rob, point1, robust_policy); geometry::recalculate(point2_rob, point2, robust_policy); // Only if this is the case the same strategy can be used. BOOST_STATIC_ASSERT((std::is_same < typename geometry::cs_tag<Point1>::type, typename geometry::cs_tag<robust_point_type>::type >::value)); return detail::equals::equals_point_point(point1_rob, point2_rob, strategy); } template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy> inline void append_no_dups_or_spikes(Range& range, Point const& point, SideStrategy const& strategy, RobustPolicy const& robust_policy) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION std::cout << " add: (" << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" << std::endl; #endif // The code below this condition checks all spikes/dups // for geometries >= 3 points. // So we have to check the first potential duplicate differently if ( boost::size(range) == 1 && points_equal_or_close(*(boost::begin(range)), point, strategy.get_equals_point_point_strategy(), robust_policy) ) { return; } traits::push_back<Range>::apply(range, point); // If a point is equal, or forming a spike, remove the pen-ultimate point // because this one caused the spike. // If so, the now-new-pen-ultimate point can again cause a spike // (possibly at a corner). So keep doing this. // Besides spikes it will also avoid adding duplicates. while(boost::size(range) >= 3 && point_is_spike_or_equal(point, *(boost::end(range) - 3), *(boost::end(range) - 2), strategy, robust_policy)) { // Use the Concept/traits, so resize and append again traits::resize<Range>::apply(range, boost::size(range) - 2); traits::push_back<Range>::apply(range, point); } } template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy> inline void append_no_collinear(Range& range, Point const& point, SideStrategy const& strategy, RobustPolicy const& robust_policy) { // Stricter version, not allowing any point in a linear row // (spike, continuation or same point) // The code below this condition checks all spikes/dups // for geometries >= 3 points. // So we have to check the first potential duplicate differently if ( boost::size(range) == 1 && points_equal_or_close(*(boost::begin(range)), point, strategy.get_equals_point_point_strategy(), robust_policy) ) { return; } traits::push_back<Range>::apply(range, point); // If a point is equal, or forming a spike, remove the pen-ultimate point // because this one caused the spike. // If so, the now-new-pen-ultimate point can again cause a spike // (possibly at a corner). So keep doing this. // Besides spikes it will also avoid adding duplicates. while(boost::size(range) >= 3 && point_is_collinear(point, *(boost::end(range) - 3), *(boost::end(range) - 2), strategy, robust_policy)) { // Use the Concept/traits, so resize and append again traits::resize<Range>::apply(range, boost::size(range) - 2); traits::push_back<Range>::apply(range, point); } } template <typename Range, typename SideStrategy, typename RobustPolicy> inline void clean_closing_dups_and_spikes(Range& range, SideStrategy const& strategy, RobustPolicy const& robust_policy) { std::size_t const minsize = core_detail::closure::minimum_ring_size < geometry::closure<Range>::value >::value; if (boost::size(range) <= minsize) { return; } typedef typename boost::range_iterator<Range>::type iterator_type; static bool const closed = geometry::closure<Range>::value == geometry::closed; // TODO: the following algorithm could be rewritten to first look for spikes // and then erase some number of points from the beginning of the Range bool found = false; do { found = false; iterator_type first = boost::begin(range); iterator_type second = first + 1; iterator_type ultimate = boost::end(range) - 1; if (BOOST_GEOMETRY_CONDITION(closed)) { ultimate--; } // Check if closing point is a spike (this is so if the second point is // considered as collinear w.r.t. the last segment) if (point_is_collinear(*second, *ultimate, *first, strategy, robust_policy)) { range::erase(range, first); if (BOOST_GEOMETRY_CONDITION(closed)) { // Remove closing last point range::resize(range, boost::size(range) - 1); // Add new closing point range::push_back(range, range::front(range)); } found = true; } } while(found && boost::size(range) > minsize); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPS_OR_SPIKES_HPP detail/overlay/pointlike_linear.hpp 0000644 00000027505 15125631657 0013554 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_OVERLAY_POINTLIKE_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_LINEAR_HPP #include <iterator> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/not.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/iterators/segment_iterator.hpp> // TEMP #include <boost/geometry/strategies/envelope/cartesian.hpp> #include <boost/geometry/strategies/envelope/geographic.hpp> #include <boost/geometry/strategies/envelope/spherical.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // difference/intersection of point-linear template < typename Point, typename Geometry, typename PointOut, overlay_type OverlayType, typename Policy > struct point_single_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Point const& point, Geometry const& geometry, RobustPolicy const&, OutputIterator oit, Strategy const& strategy) { action_selector_pl < PointOut, OverlayType >::apply(point, Policy::apply(point, geometry, strategy), oit); return oit; } }; // difference/intersection of multipoint-segment template < typename MultiPoint, typename Geometry, typename PointOut, overlay_type OverlayType, typename Policy > struct multipoint_single_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(MultiPoint const& multipoint, Geometry const& geometry, RobustPolicy const&, OutputIterator oit, Strategy const& strategy) { for (typename boost::range_iterator<MultiPoint const>::type it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { action_selector_pl < PointOut, OverlayType >::apply(*it, Policy::apply(*it, geometry, strategy), oit); } return oit; } }; // difference/intersection of multipoint-linear template < typename MultiPoint, typename Linear, typename PointOut, overlay_type OverlayType, typename Policy > class multipoint_linear_point { private: // structs for partition -- start template <typename ExpandPointStrategy> struct expand_box_point { template <typename Box, typename Point> static inline void apply(Box& total, Point const& point) { geometry::expand(total, point, ExpandPointStrategy()); } }; template <typename EnvelopeStrategy> struct expand_box_segment { explicit expand_box_segment(EnvelopeStrategy const& strategy) : m_strategy(strategy) {} template <typename Box, typename Segment> inline void apply(Box& total, Segment const& segment) const { geometry::expand(total, geometry::return_envelope<Box>(segment, m_strategy), // TEMP - envelope umbrella strategy also contains // expand strategies strategies::envelope::services::strategy_converter < EnvelopeStrategy >::get(m_strategy)); } EnvelopeStrategy const& m_strategy; }; template <typename DisjointPointBoxStrategy> struct overlaps_box_point { template <typename Box, typename Point> static inline bool apply(Box const& box, Point const& point) { return ! geometry::disjoint(point, box, DisjointPointBoxStrategy()); } }; template <typename DisjointStrategy> struct overlaps_box_segment { explicit overlaps_box_segment(DisjointStrategy const& strategy) : m_strategy(strategy) {} template <typename Box, typename Segment> inline bool apply(Box const& box, Segment const& segment) const { return ! geometry::disjoint(segment, box, m_strategy); } DisjointStrategy const& m_strategy; }; template <typename OutputIterator, typename Strategy> class item_visitor_type { public: item_visitor_type(OutputIterator& oit, Strategy const& strategy) : m_oit(oit) , m_strategy(strategy) {} template <typename Item1, typename Item2> inline bool apply(Item1 const& item1, Item2 const& item2) { action_selector_pl < PointOut, overlay_intersection >::apply(item1, Policy::apply(item1, item2, m_strategy), m_oit); return true; } private: OutputIterator& m_oit; Strategy const& m_strategy; }; // structs for partition -- end class segment_range { public: typedef geometry::segment_iterator<Linear const> const_iterator; typedef const_iterator iterator; segment_range(Linear const& linear) : m_linear(linear) {} const_iterator begin() const { return geometry::segments_begin(m_linear); } const_iterator end() const { return geometry::segments_end(m_linear); } private: Linear const& m_linear; }; template <typename OutputIterator, typename Strategy> static inline OutputIterator get_common_points(MultiPoint const& multipoint, Linear const& linear, OutputIterator oit, Strategy const& strategy) { item_visitor_type<OutputIterator, Strategy> item_visitor(oit, strategy); typedef typename Strategy::envelope_strategy_type envelope_strategy_type; typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type; typedef typename Strategy::disjoint_point_box_strategy_type disjoint_point_box_strategy_type; typedef typename Strategy::expand_point_strategy_type expand_point_strategy_type; // TODO: disjoint Segment/Box may be called in partition multiple times // possibly for non-cartesian segments which could be slow. We should consider // passing a range of bounding boxes of segments after calculating them once. // Alternatively instead of a range of segments a range of Segment/Envelope pairs // should be passed, where envelope would be lazily calculated when needed the first time geometry::partition < geometry::model::box < typename boost::range_value<MultiPoint>::type > >::apply(multipoint, segment_range(linear), item_visitor, expand_box_point<expand_point_strategy_type>(), overlaps_box_point<disjoint_point_box_strategy_type>(), expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()), overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy())); return oit; } public: template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(MultiPoint const& multipoint, Linear const& linear, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { typedef std::vector < typename boost::range_value<MultiPoint>::type > point_vector_type; point_vector_type common_points; // compute the common points get_common_points(multipoint, linear, std::back_inserter(common_points), strategy); return multipoint_multipoint_point < MultiPoint, point_vector_type, PointOut, OverlayType >::apply(multipoint, common_points, robust_policy, oit, strategy); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { namespace overlay { // dispatch struct for pointlike-linear difference/intersection computation template < typename PointLike, typename Linear, typename PointOut, overlay_type OverlayType, typename Tag1, typename Tag2 > struct pointlike_linear_point : not_implemented<PointLike, Linear, PointOut> {}; template < typename Point, typename Linear, typename PointOut, overlay_type OverlayType > struct pointlike_linear_point < Point, Linear, PointOut, OverlayType, point_tag, linear_tag > : detail::overlay::point_single_point < Point, Linear, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; template < typename Point, typename Segment, typename PointOut, overlay_type OverlayType > struct pointlike_linear_point < Point, Segment, PointOut, OverlayType, point_tag, segment_tag > : detail::overlay::point_single_point < Point, Segment, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; template < typename MultiPoint, typename Linear, typename PointOut, overlay_type OverlayType > struct pointlike_linear_point < MultiPoint, Linear, PointOut, OverlayType, multi_point_tag, linear_tag > : detail::overlay::multipoint_linear_point < MultiPoint, Linear, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; template < typename MultiPoint, typename Segment, typename PointOut, overlay_type OverlayType > struct pointlike_linear_point < MultiPoint, Segment, PointOut, OverlayType, multi_point_tag, segment_tag > : detail::overlay::multipoint_single_point < MultiPoint, Segment, PointOut, OverlayType, detail::not_<detail::disjoint::reverse_covered_by> > {}; }} // namespace detail_dispatch::overlay #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_LINEAR_HPP detail/overlay/sort_by_side.hpp 0000644 00000053310 15125631657 0012702 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017, 2019. // Modifications copyright (c) 2017, 2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_BY_SIDE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_BY_SIDE_HPP #include <algorithm> #include <map> #include <vector> #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/direction_code.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { namespace sort_by_side { enum direction_type { dir_unknown = -1, dir_from = 0, dir_to = 1 }; typedef signed_size_type rank_type; // Point-wrapper, adding some properties template <typename Point> struct ranked_point { ranked_point() : rank(0) , turn_index(-1) , operation_index(-1) , direction(dir_unknown) , count_left(0) , count_right(0) , operation(operation_none) {} ranked_point(Point const& p, signed_size_type ti, int oi, direction_type d, operation_type op, segment_identifier const& si) : point(p) , rank(0) , zone(-1) , turn_index(ti) , operation_index(oi) , direction(d) , count_left(0) , count_right(0) , operation(op) , seg_id(si) {} Point point; rank_type rank; signed_size_type zone; // index of closed zone, in uu turn there would be 2 zones signed_size_type turn_index; int operation_index; // 0,1 direction_type direction; std::size_t count_left; std::size_t count_right; operation_type operation; segment_identifier seg_id; }; struct less_by_turn_index { template <typename T> inline bool operator()(const T& first, const T& second) const { return first.turn_index == second.turn_index ? first.index < second.index : first.turn_index < second.turn_index ; } }; struct less_by_index { template <typename T> inline bool operator()(const T& first, const T& second) const { // Length might be considered too // First order by from/to if (first.direction != second.direction) { return first.direction < second.direction; } // Then by turn index if (first.turn_index != second.turn_index) { return first.turn_index < second.turn_index; } // This can also be the same (for example in buffer), but seg_id is // never the same return first.seg_id < second.seg_id; } }; struct less_false { template <typename T> inline bool operator()(const T&, const T& ) const { return false; } }; template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare> struct less_by_side { less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy) : m_origin(p1) , m_turn_point(p2) , m_strategy(strategy) {} template <typename T> inline bool operator()(const T& first, const T& second) const { typedef typename SideStrategy::cs_tag cs_tag; LessOnSame on_same; Compare compare; int const side_first = m_strategy.apply(m_origin, m_turn_point, first.point); int const side_second = m_strategy.apply(m_origin, m_turn_point, second.point); if (side_first == 0 && side_second == 0) { // Both collinear. They might point into different directions: <------*------> // If so, order the one going backwards as the very first. int const first_code = direction_code<cs_tag>(m_origin, m_turn_point, first.point); int const second_code = direction_code<cs_tag>(m_origin, m_turn_point, second.point); // Order by code, backwards first, then forward. return first_code != second_code ? first_code < second_code : on_same(first, second) ; } else if (side_first == 0 && direction_code<cs_tag>(m_origin, m_turn_point, first.point) == -1) { // First collinear and going backwards. // Order as the very first, so return always true return true; } else if (side_second == 0 && direction_code<cs_tag>(m_origin, m_turn_point, second.point) == -1) { // Second is collinear and going backwards // Order as very last, so return always false return false; } // They are not both collinear if (side_first != side_second) { return compare(side_first, side_second); } // They are both left, both right, and/or both collinear (with each other and/or with p1,p2) // Check mutual side int const side_second_wrt_first = m_strategy.apply(m_turn_point, first.point, second.point); if (side_second_wrt_first == 0) { return on_same(first, second); } int const side_first_wrt_second = m_strategy.apply(m_turn_point, second.point, first.point); if (side_second_wrt_first != -side_first_wrt_second) { // (FP) accuracy error in side calculation, the sides are not opposite. // In that case they can be handled as collinear. // If not, then the sort-order might not be stable. return on_same(first, second); } // Both are on same side, and not collinear // Union: return true if second is right w.r.t. first, so -1, // so other is 1. union has greater as compare functor // Intersection: v.v. return compare(side_first_wrt_second, side_second_wrt_first); } private : Point const& m_origin; Point const& m_turn_point; SideStrategy const& m_strategy; }; // Sorts vectors in counter clockwise order (by default) template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Point, typename SideStrategy, typename Compare > struct side_sorter { typedef ranked_point<Point> rp; private : struct include_union { inline bool operator()(rp const& ranked_point) const { // New candidate if there are no polygons on left side, // but there are on right side return ranked_point.count_left == 0 && ranked_point.count_right > 0; } }; struct include_intersection { inline bool operator()(rp const& ranked_point) const { // New candidate if there are two polygons on right side, // and less on the left side return ranked_point.count_left < 2 && ranked_point.count_right >= 2; } }; public : side_sorter(SideStrategy const& strategy) : m_origin_count(0) , m_origin_segment_distance(0) , m_strategy(strategy) {} void add_segment_from(signed_size_type turn_index, int op_index, Point const& point_from, operation_type op, segment_identifier const& si, bool is_origin) { m_ranked_points.push_back(rp(point_from, turn_index, op_index, dir_from, op, si)); if (is_origin) { m_origin = point_from; m_origin_count++; } } void add_segment_to(signed_size_type turn_index, int op_index, Point const& point_to, operation_type op, segment_identifier const& si) { m_ranked_points.push_back(rp(point_to, turn_index, op_index, dir_to, op, si)); } void add_segment(signed_size_type turn_index, int op_index, Point const& point_from, Point const& point_to, operation_type op, segment_identifier const& si, bool is_origin) { add_segment_from(turn_index, op_index, point_from, op, si, is_origin); add_segment_to(turn_index, op_index, point_to, op, si); } template <typename Operation, typename Geometry1, typename Geometry2> Point add(Operation const& op, signed_size_type turn_index, int op_index, Geometry1 const& geometry1, Geometry2 const& geometry2, bool is_origin) { Point point1, point2, point3; geometry::copy_segment_points<Reverse1, Reverse2>(geometry1, geometry2, op.seg_id, point1, point2, point3); Point const& point_to = op.fraction.is_one() ? point3 : point2; add_segment(turn_index, op_index, point1, point_to, op.operation, op.seg_id, is_origin); return point1; } template <typename Operation, typename Geometry1, typename Geometry2> void add(Operation const& op, signed_size_type turn_index, int op_index, segment_identifier const& departure_seg_id, Geometry1 const& geometry1, Geometry2 const& geometry2, bool check_origin) { Point const point1 = add(op, turn_index, op_index, geometry1, geometry2, false); if (check_origin) { bool const is_origin = op.seg_id.source_index == departure_seg_id.source_index && op.seg_id.ring_index == departure_seg_id.ring_index && op.seg_id.multi_index == departure_seg_id.multi_index; if (is_origin) { signed_size_type const segment_distance = calculate_segment_distance(op, departure_seg_id, geometry1, geometry2); if (m_origin_count == 0 || segment_distance < m_origin_segment_distance) { m_origin = point1; m_origin_segment_distance = segment_distance; } m_origin_count++; } } } template <typename Operation, typename Geometry1, typename Geometry2> static signed_size_type calculate_segment_distance(Operation const& op, segment_identifier const& departure_seg_id, Geometry1 const& geometry1, Geometry2 const& geometry2) { if (op.seg_id.segment_index >= departure_seg_id.segment_index) { // dep.seg_id=5, op.seg_id=7, distance=2, being segments 5,6 return op.seg_id.segment_index - departure_seg_id.segment_index; } // Take wrap into account // Suppose point_count=10 (10 points, 9 segments), dep.seg_id=7, op.seg_id=2, // then distance=9-7+2=4, being segments 7,8,0,1 std::size_t const segment_count = op.seg_id.source_index == 0 ? segment_count_on_ring(geometry1, op.seg_id) : segment_count_on_ring(geometry2, op.seg_id); return segment_count - departure_seg_id.segment_index + op.seg_id.segment_index; } void apply(Point const& turn_point) { // We need three compare functors: // 1) to order clockwise (union) or counter clockwise (intersection) // 2) to order by side, resulting in unique ranks for all points // 3) to order by side, resulting in non-unique ranks // to give colinear points // Sort by side and assign rank less_by_side<Point, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy); less_by_side<Point, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy); std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique); std::size_t colinear_rank = 0; for (std::size_t i = 0; i < m_ranked_points.size(); i++) { if (i > 0 && less_non_unique(m_ranked_points[i - 1], m_ranked_points[i])) { // It is not collinear colinear_rank++; } m_ranked_points[i].rank = colinear_rank; } } void find_open_by_piece_index() { // For buffers, use piece index std::set<signed_size_type> handled; for (std::size_t i = 0; i < m_ranked_points.size(); i++) { const rp& ranked = m_ranked_points[i]; if (ranked.direction != dir_from) { continue; } signed_size_type const& index = ranked.seg_id.piece_index; if (handled.count(index) > 0) { continue; } find_polygons_for_source<&segment_identifier::piece_index>(index, i); handled.insert(index); } } void find_open_by_source_index() { // Check for source index 0 and 1 bool handled[2] = {false, false}; for (std::size_t i = 0; i < m_ranked_points.size(); i++) { const rp& ranked = m_ranked_points[i]; if (ranked.direction != dir_from) { continue; } signed_size_type const& index = ranked.seg_id.source_index; if (index < 0 || index > 1 || handled[index]) { continue; } find_polygons_for_source<&segment_identifier::source_index>(index, i); handled[index] = true; } } void find_open() { if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer)) { find_open_by_piece_index(); } else { find_open_by_source_index(); } } void reverse() { if (m_ranked_points.empty()) { return; } std::size_t const last = 1 + m_ranked_points.back().rank; // Move iterator after rank==0 bool has_first = false; typename container_type::iterator it = m_ranked_points.begin() + 1; for (; it != m_ranked_points.end() && it->rank == 0; ++it) { has_first = true; } if (has_first) { // Reverse first part (having rank == 0), if any, // but skip the very first row std::reverse(m_ranked_points.begin() + 1, it); for (typename container_type::iterator fit = m_ranked_points.begin(); fit != it; ++fit) { BOOST_ASSERT(fit->rank == 0); } } // Reverse the rest (main rank > 0) std::reverse(it, m_ranked_points.end()); for (; it != m_ranked_points.end(); ++it) { BOOST_ASSERT(it->rank > 0); it->rank = last - it->rank; } } bool has_origin() const { return m_origin_count > 0; } //private : typedef std::vector<rp> container_type; container_type m_ranked_points; Point m_origin; std::size_t m_origin_count; signed_size_type m_origin_segment_distance; SideStrategy m_strategy; private : //! Check how many open spaces there are template <typename Include> inline std::size_t open_count(Include const& include_functor) const { std::size_t result = 0; rank_type last_rank = 0; for (std::size_t i = 0; i < m_ranked_points.size(); i++) { rp const& ranked_point = m_ranked_points[i]; if (ranked_point.rank > last_rank && ranked_point.direction == sort_by_side::dir_to && include_functor(ranked_point)) { result++; last_rank = ranked_point.rank; } } return result; } std::size_t move(std::size_t index) const { std::size_t const result = index + 1; return result >= m_ranked_points.size() ? 0 : result; } //! member is pointer to member (source_index or multi_index) template <signed_size_type segment_identifier::*Member> std::size_t move(signed_size_type member_index, std::size_t index) const { std::size_t result = move(index); while (m_ranked_points[result].seg_id.*Member != member_index) { result = move(result); } return result; } void assign_ranks(rank_type min_rank, rank_type max_rank, int side_index) { for (std::size_t i = 0; i < m_ranked_points.size(); i++) { rp& ranked = m_ranked_points[i]; // Suppose there are 8 ranks, if min=4,max=6: assign 4,5,6 // if min=5,max=2: assign from 5,6,7,1,2 bool const in_range = max_rank >= min_rank ? ranked.rank >= min_rank && ranked.rank <= max_rank : ranked.rank >= min_rank || ranked.rank <= max_rank ; if (in_range) { if (side_index == 1) { ranked.count_left++; } else if (side_index == 2) { ranked.count_right++; } } } } template <signed_size_type segment_identifier::*Member> void find_polygons_for_source(signed_size_type the_index, std::size_t start_index) { bool in_polygon = true; // Because start_index is "from", arrives at the turn rp const& start_rp = m_ranked_points[start_index]; rank_type last_from_rank = start_rp.rank; rank_type previous_rank = start_rp.rank; for (std::size_t index = move<Member>(the_index, start_index); ; index = move<Member>(the_index, index)) { rp& ranked = m_ranked_points[index]; if (ranked.rank != previous_rank && ! in_polygon) { assign_ranks(last_from_rank, previous_rank - 1, 1); assign_ranks(last_from_rank + 1, previous_rank, 2); } if (index == start_index) { return; } if (ranked.direction == dir_from) { last_from_rank = ranked.rank; in_polygon = true; } else if (ranked.direction == dir_to) { in_polygon = false; } previous_rank = ranked.rank; } } //! Find closed zones and assign it template <typename Include> std::size_t assign_zones(Include const& include_functor) { // Find a starting point (the first rank after an outgoing rank // with no polygons on the left side) rank_type start_rank = m_ranked_points.size() + 1; std::size_t start_index = 0; rank_type max_rank = 0; for (std::size_t i = 0; i < m_ranked_points.size(); i++) { rp const& ranked_point = m_ranked_points[i]; if (ranked_point.rank > max_rank) { max_rank = ranked_point.rank; } if (ranked_point.direction == sort_by_side::dir_to && include_functor(ranked_point)) { start_rank = ranked_point.rank + 1; } if (ranked_point.rank == start_rank && start_index == 0) { start_index = i; } } // Assign the zones rank_type const undefined_rank = max_rank + 1; std::size_t zone_id = 0; rank_type last_rank = 0; rank_type rank_at_next_zone = undefined_rank; std::size_t index = start_index; for (std::size_t i = 0; i < m_ranked_points.size(); i++) { rp& ranked_point = m_ranked_points[index]; // Implement cyclic behavior index++; if (index == m_ranked_points.size()) { index = 0; } if (ranked_point.rank != last_rank) { if (ranked_point.rank == rank_at_next_zone) { zone_id++; rank_at_next_zone = undefined_rank; } if (ranked_point.direction == sort_by_side::dir_to && include_functor(ranked_point)) { rank_at_next_zone = ranked_point.rank + 1; if (rank_at_next_zone > max_rank) { rank_at_next_zone = 0; } } last_rank = ranked_point.rank; } ranked_point.zone = zone_id; } return zone_id; } public : inline std::size_t open_count(operation_type for_operation) const { return for_operation == operation_union ? open_count(include_union()) : open_count(include_intersection()) ; } inline std::size_t assign_zones(operation_type for_operation) { return for_operation == operation_union ? assign_zones(include_union()) : assign_zones(include_intersection()) ; } }; //! Metafunction to define side_order (clockwise, ccw) by operation_type template <operation_type OpType> struct side_compare {}; template <> struct side_compare<operation_union> { typedef std::greater<int> type; }; template <> struct side_compare<operation_intersection> { typedef std::less<int> type; }; }}} // namespace detail::overlay::sort_by_side #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_BY_SIDE_HPP detail/overlay/enrichment_info.hpp 0000644 00000004447 15125631657 0013373 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP #include <boost/geometry/algorithms/detail/signed_size_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { /*! \brief Keeps info to enrich intersection info (per source) \details Class to keep information necessary for traversal phase (a phase of the overlay process). The information is gathered during the enrichment phase */ template<typename Point> struct enrichment_info { inline enrichment_info() : travels_to_vertex_index(-1) , travels_to_ip_index(-1) , next_ip_index(-1) , startable(true) , prefer_start(true) , count_left(0) , count_right(0) , rank(-1) , zone(-1) , region_id(-1) , isolated(false) {} inline signed_size_type get_next_turn_index() const { return next_ip_index == -1 ? travels_to_ip_index : next_ip_index; } // vertex to which is free travel after this IP, // so from "segment_index+1" to "travels_to_vertex_index", without IP-s, // can be -1 signed_size_type travels_to_vertex_index; // same but now IP index, so "next IP index" but not on THIS segment signed_size_type travels_to_ip_index; // index of next IP on this segment, -1 if there is no one signed_size_type next_ip_index; bool startable; // Can be used to start in traverse bool prefer_start; // Is preferred as starting point (if true) // Counts if polygons left/right of this operation std::size_t count_left; std::size_t count_right; signed_size_type rank; // in cluster signed_size_type zone; // open zone, in cluster signed_size_type region_id; bool isolated; }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP detail/overlay/traversal.hpp 0000644 00000103312 15125631657 0012216 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP #include <cstddef> #include <set> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_exits.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \ || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \ || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) # include <string> # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> # include <boost/geometry/io/wkt/wkt.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Turn, typename Operation> #ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE inline void debug_traverse(Turn const& turn, Operation op, std::string const& header, bool condition = true) { if (! condition) { return; } std::cout << " " << header << " at " << op.seg_id << " meth: " << method_char(turn.method) << " op: " << operation_char(op.operation) << " vis: " << visited_char(op.visited) << " of: " << operation_char(turn.operations[0].operation) << operation_char(turn.operations[1].operation) << " " << geometry::wkt(turn.point) << std::endl; if (boost::contains(header, "Finished")) { std::cout << std::endl; } } #else inline void debug_traverse(Turn const& , Operation, const char*, bool = true) { } #endif template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Geometry1, typename Geometry2, typename Turns, typename Clusters, typename RobustPolicy, typename SideStrategy, typename Visitor > struct traversal { private : static const operation_type target_operation = operation_from_overlay<OverlayType>::value; typedef typename sort_by_side::side_compare<target_operation>::type side_compare_type; typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; typedef typename geometry::point_type<Geometry1>::type point_type; typedef sort_by_side::side_sorter < Reverse1, Reverse2, OverlayType, point_type, SideStrategy, side_compare_type > sbs_type; public : inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, Clusters const& clusters, RobustPolicy const& robust_policy, SideStrategy const& strategy, Visitor& visitor) : m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) , m_clusters(clusters) , m_robust_policy(robust_policy) , m_strategy(strategy) , m_visitor(visitor) { } template <typename TurnInfoMap> inline void finalize_visit_info(TurnInfoMap& turn_info_map) { for (typename boost::range_iterator<Turns>::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it) { turn_type& turn = *it; for (int i = 0; i < 2; i++) { turn_operation_type& op = turn.operations[i]; if (op.visited.visited() || op.visited.started() || op.visited.finished() ) { ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id); turn_info_map[ring_id].has_traversed_turn = true; if (op.operation == operation_continue) { // Continue operations should mark the other operation // as traversed too turn_operation_type& other_op = turn.operations[1 - i]; ring_identifier const other_ring_id = ring_id_by_seg_id(other_op.seg_id); turn_info_map[other_ring_id].has_traversed_turn = true; } } op.visited.finalize(); } } } //! Sets visited for ALL turns traveling to the same turn inline void set_visited_in_cluster(signed_size_type cluster_id, signed_size_type rank) { typename Clusters::const_iterator mit = m_clusters.find(cluster_id); BOOST_ASSERT(mit != m_clusters.end()); cluster_info const& cinfo = mit->second; std::set<signed_size_type> const& ids = cinfo.turn_indices; for (typename std::set<signed_size_type>::const_iterator it = ids.begin(); it != ids.end(); ++it) { signed_size_type const turn_index = *it; turn_type& turn = m_turns[turn_index]; for (int i = 0; i < 2; i++) { turn_operation_type& op = turn.operations[i]; if (op.visited.none() && op.enriched.rank == rank) { op.visited.set_visited(); } } } } inline void set_visited(turn_type& turn, turn_operation_type& op) { if (op.operation == detail::overlay::operation_continue) { // On "continue", all go in same direction so set "visited" for ALL for (int i = 0; i < 2; i++) { turn_operation_type& turn_op = turn.operations[i]; if (turn_op.visited.none()) { turn_op.visited.set_visited(); } } } else { op.visited.set_visited(); } if (turn.is_clustered()) { set_visited_in_cluster(turn.cluster_id, op.enriched.rank); } } inline bool is_visited(turn_type const& , turn_operation_type const& op, signed_size_type , int) const { return op.visited.visited(); } template <signed_size_type segment_identifier::*Member> inline bool select_source_generic(turn_type const& turn, segment_identifier const& current, segment_identifier const& previous) const { turn_operation_type const& op0 = turn.operations[0]; turn_operation_type const& op1 = turn.operations[1]; bool const switch_source = op0.enriched.region_id != -1 && op0.enriched.region_id == op1.enriched.region_id; #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR) if (switch_source) { std::cout << "Switch source at " << &turn << std::endl; } else { std::cout << "DON'T SWITCH SOURCES at " << &turn << std::endl; } #endif return switch_source ? current.*Member != previous.*Member : current.*Member == previous.*Member; } inline bool select_source(turn_type const& turn, segment_identifier const& candidate_seg_id, segment_identifier const& previous_seg_id) const { // For uu/ii, only switch sources if indicated if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer)) { // Buffer does not use source_index (always 0). return select_source_generic<&segment_identifier::multi_index>( turn, candidate_seg_id, previous_seg_id); } if (is_self_turn<OverlayType>(turn)) { // Also, if it is a self-turn, stay on same ring (multi/ring) return select_source_generic<&segment_identifier::multi_index>( turn, candidate_seg_id, previous_seg_id); } // Use source_index return select_source_generic<&segment_identifier::source_index>( turn, candidate_seg_id, previous_seg_id); } inline bool traverse_possible(signed_size_type turn_index) const { if (turn_index == -1) { return false; } turn_type const& turn = m_turns[turn_index]; // It is not a dead end if there is an operation to continue, or of // there is a cluster (assuming for now we can get out of the cluster) return turn.is_clustered() || turn.has(target_operation) || turn.has(operation_continue); } inline std::size_t get_shortcut_level(turn_operation_type const& op, signed_size_type start_turn_index, signed_size_type origin_turn_index, std::size_t level = 1) const { signed_size_type next_turn_index = op.enriched.get_next_turn_index(); if (next_turn_index == -1) { return 0; } if (next_turn_index == start_turn_index) { // This operation finishes the ring return 0; } if (next_turn_index == origin_turn_index) { // This operation travels to itself return level; } if (level > 10) { // Avoid infinite recursion return 0; } turn_type const& next_turn = m_turns[next_turn_index]; for (int i = 0; i < 2; i++) { turn_operation_type const& next_op = next_turn.operations[i]; if (next_op.operation == target_operation && ! next_op.visited.finished() && ! next_op.visited.visited()) { // Recursively continue verifying if (get_shortcut_level(next_op, start_turn_index, origin_turn_index, level + 1)) { return level + 1; } } } return 0; } inline bool select_cc_operation(turn_type const& turn, signed_size_type start_turn_index, int& selected_op_index) const { // For "cc", take either one, but if there is a starting one, // take that one. If next is dead end, skip that one. // If both are valid candidates, take the one with minimal remaining // distance (important for #mysql_23023665 in buffer). signed_size_type next[2] = {0}; bool possible[2] = {0}; bool close[2] = {0}; for (int i = 0; i < 2; i++) { next[i] = turn.operations[i].enriched.get_next_turn_index(); possible[i] = traverse_possible(next[i]); close[i] = possible[i] && next[i] == start_turn_index; } if (close[0] != close[1]) { // One of the operations will finish the ring. Take that one. selected_op_index = close[0] ? 0 : 1; debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc closing"); return true; } if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer) && possible[0] && possible[1]) { // Buffers sometimes have multiple overlapping pieces, where remaining // distance could lead to the wrong choice. Take the matching operation. bool is_target[2] = {0}; for (int i = 0; i < 2; i++) { turn_operation_type const& next_op = m_turns[next[i]].operations[i]; is_target[i] = next_op.operation == target_operation; } if (is_target[0] != is_target[1]) { // Take the matching operation selected_op_index = is_target[0] ? 0 : 1; debug_traverse(turn, turn.operations[selected_op_index], "Candidate cc target"); return true; } } static bool const is_union = target_operation == operation_union; typename turn_operation_type::comparable_distance_type best_remaining_distance = 0; bool result = false; for (int i = 0; i < 2; i++) { if (!possible[i]) { continue; } turn_operation_type const& op = turn.operations[i]; if (! result || (is_union && op.remaining_distance > best_remaining_distance) || (!is_union && op.remaining_distance < best_remaining_distance)) { debug_traverse(turn, op, "First candidate cc", ! result); debug_traverse(turn, op, "Candidate cc override (remaining)", result && op.remaining_distance < best_remaining_distance); selected_op_index = i; best_remaining_distance = op.remaining_distance; result = true; } } return result; } inline bool select_noncc_operation(turn_type const& turn, segment_identifier const& previous_seg_id, int& selected_op_index) const { bool result = false; for (int i = 0; i < 2; i++) { turn_operation_type const& op = turn.operations[i]; if (op.operation == target_operation && ! op.visited.finished() && ! op.visited.visited() && (! result || select_source(turn, op.seg_id, previous_seg_id))) { selected_op_index = i; debug_traverse(turn, op, "Candidate"); result = true; } } return result; } inline bool select_preferred_operation(turn_type const& turn, signed_size_type turn_index, signed_size_type start_turn_index, int& selected_op_index) const { bool option[2] = {0}; bool finishing[2] = {0}; bool preferred[2] = {0}; std::size_t shortcut_level[2] = {0}; for (int i = 0; i < 2; i++) { turn_operation_type const& op = turn.operations[i]; if (op.operation == target_operation && ! op.visited.finished() && ! op.visited.visited()) { option[i] = true; if (op.enriched.get_next_turn_index() == start_turn_index) { finishing[i] = true; } else { shortcut_level[i] = get_shortcut_level(op, start_turn_index, turn_index); } if (op.enriched.prefer_start) { preferred[i] = true; } } } if (option[0] != option[1]) { // Only one operation is acceptable, take that one selected_op_index = option[0] ? 0 : 1; return true; } if (option[0] && option[1]) { // Both operations are acceptable if (finishing[0] != finishing[1]) { // Prefer operation finishing the ring selected_op_index = finishing[0] ? 0 : 1; return true; } if (shortcut_level[0] != shortcut_level[1]) { // If a turn can travel to itself again (without closing the // ring), take the shortest one selected_op_index = shortcut_level[0] < shortcut_level[1] ? 0 : 1; return true; } if (preferred[0] != preferred[1]) { // Only one operation is preferred (== was not intersection) selected_op_index = preferred[0] ? 0 : 1; return true; } } for (int i = 0; i < 2; i++) { if (option[i]) { selected_op_index = 0; return true; } } return false; } inline bool select_operation(const turn_type& turn, signed_size_type turn_index, signed_size_type start_turn_index, segment_identifier const& previous_seg_id, int& selected_op_index) const { bool result = false; selected_op_index = -1; if (turn.both(operation_continue)) { result = select_cc_operation(turn, start_turn_index, selected_op_index); } else if (BOOST_GEOMETRY_CONDITION(OverlayType == overlay_dissolve)) { result = select_preferred_operation(turn, turn_index, start_turn_index, selected_op_index); } else { result = select_noncc_operation(turn, previous_seg_id, selected_op_index); } if (result) { debug_traverse(turn, turn.operations[selected_op_index], "Accepted"); } return result; } inline int starting_operation_index(const turn_type& turn) const { for (int i = 0; i < 2; i++) { if (turn.operations[i].visited.started()) { return i; } } return -1; } inline bool both_finished(const turn_type& turn) const { for (int i = 0; i < 2; i++) { if (! turn.operations[i].visited.finished()) { return false; } } return true; } template <typename RankedPoint> inline turn_operation_type const& operation_from_rank(RankedPoint const& rp) const { return m_turns[rp.turn_index].operations[rp.operation_index]; } inline int select_turn_in_cluster_union(sort_by_side::rank_type selected_rank, typename sbs_type::rp const& ranked_point, signed_size_type start_turn_index, int start_op_index) const { // Returns 0 if it not OK // Returns 1 if it OK // Returns 2 if it OK and start turn matches // Returns 3 if it OK and start turn and start op both match if (ranked_point.rank != selected_rank || ranked_point.direction != sort_by_side::dir_to) { return 0; } turn_operation_type const& op = operation_from_rank(ranked_point); // Check finalized: TODO: this should be finetuned, it is not necessary if (op.visited.finalized()) { return 0; } if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_dissolve) && (op.enriched.count_left != 0 || op.enriched.count_right == 0)) { // Check counts: in some cases interior rings might be generated with // polygons on both sides. For dissolve it can be anything. return 0; } return ranked_point.turn_index == start_turn_index && ranked_point.operation_index == start_op_index ? 3 : ranked_point.turn_index == start_turn_index ? 2 : 1 ; } inline sort_by_side::rank_type select_rank(sbs_type const& sbs, bool skip_isolated) const { // Take the first outgoing rank corresponding to incoming region, // or take another region if it is not isolated turn_operation_type const& incoming_op = operation_from_rank(sbs.m_ranked_points.front()); for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { typename sbs_type::rp const& rp = sbs.m_ranked_points[i]; if (rp.rank == 0 || rp.direction == sort_by_side::dir_from) { continue; } turn_operation_type const& op = operation_from_rank(rp); if (op.operation != target_operation && op.operation != operation_continue) { continue; } if (op.enriched.region_id == incoming_op.enriched.region_id || (skip_isolated && ! op.enriched.isolated)) { // Region corresponds to incoming region, or (for intersection) // there is a non-isolated other region which should be taken return rp.rank; } } return -1; } inline bool select_from_cluster_union(signed_size_type& turn_index, int& op_index, sbs_type const& sbs, signed_size_type start_turn_index, int start_op_index) const { sort_by_side::rank_type const selected_rank = select_rank(sbs, false); int best_code = 0; bool result = false; for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++) { typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; if (ranked_point.rank > selected_rank) { // Sorted on rank, so it makes no sense to continue break; } int const code = select_turn_in_cluster_union(selected_rank, ranked_point, start_turn_index, start_op_index); if (code > best_code) { // It is 1 or higher and matching better than previous best_code = code; turn_index = ranked_point.turn_index; op_index = ranked_point.operation_index; result = true; } } return result; } inline bool analyze_cluster_intersection(signed_size_type& turn_index, int& op_index, sbs_type const& sbs) const { sort_by_side::rank_type const selected_rank = select_rank(sbs, true); if (selected_rank > 0) { typename turn_operation_type::comparable_distance_type min_remaining_distance = 0; std::size_t selected_index = sbs.m_ranked_points.size(); for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i]; if (ranked_point.rank == selected_rank) { turn_operation_type const& op = operation_from_rank(ranked_point); if (op.visited.finalized()) { // This direction is already traveled before, the same // cannot be traveled again continue; } // Take turn with the smallest remaining distance if (selected_index == sbs.m_ranked_points.size() || op.remaining_distance < min_remaining_distance) { selected_index = i; min_remaining_distance = op.remaining_distance; } } } if (selected_index < sbs.m_ranked_points.size()) { typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[selected_index]; turn_index = ranked_point.turn_index; op_index = ranked_point.operation_index; return true; } } return false; } inline bool fill_sbs(sbs_type& sbs, signed_size_type turn_index, std::set<signed_size_type> const& ids, segment_identifier const& previous_seg_id) const { for (typename std::set<signed_size_type>::const_iterator sit = ids.begin(); sit != ids.end(); ++sit) { signed_size_type cluster_turn_index = *sit; turn_type const& cluster_turn = m_turns[cluster_turn_index]; bool const departure_turn = cluster_turn_index == turn_index; if (cluster_turn.discarded) { // Defensive check, discarded turns should not be in cluster continue; } for (int i = 0; i < 2; i++) { sbs.add(cluster_turn.operations[i], cluster_turn_index, i, previous_seg_id, m_geometry1, m_geometry2, departure_turn); } } if (! sbs.has_origin()) { return false; } turn_type const& turn = m_turns[turn_index]; sbs.apply(turn.point); return true; } inline bool select_turn_from_cluster(signed_size_type& turn_index, int& op_index, signed_size_type start_turn_index, int start_op_index, segment_identifier const& previous_seg_id) const { bool const is_union = target_operation == operation_union; turn_type const& turn = m_turns[turn_index]; BOOST_ASSERT(turn.is_clustered()); typename Clusters::const_iterator mit = m_clusters.find(turn.cluster_id); BOOST_ASSERT(mit != m_clusters.end()); cluster_info const& cinfo = mit->second; std::set<signed_size_type> const& ids = cinfo.turn_indices; sbs_type sbs(m_strategy); if (! fill_sbs(sbs, turn_index, ids, previous_seg_id)) { return false; } cluster_exits<OverlayType, Turns, sbs_type> exits(m_turns, ids, sbs); if (exits.apply(turn_index, op_index)) { return true; } bool result = false; if (is_union) { result = select_from_cluster_union(turn_index, op_index, sbs, start_turn_index, start_op_index); if (! result) { // There no way out found, try second pass in collected cluster exits result = exits.apply(turn_index, op_index, false); } } else { result = analyze_cluster_intersection(turn_index, op_index, sbs); } return result; } inline bool analyze_ii_intersection(signed_size_type& turn_index, int& op_index, turn_type const& current_turn, segment_identifier const& previous_seg_id) { sbs_type sbs(m_strategy); // Add this turn to the sort-by-side sorter for (int i = 0; i < 2; i++) { sbs.add(current_turn.operations[i], turn_index, i, previous_seg_id, m_geometry1, m_geometry2, true); } if (! sbs.has_origin()) { return false; } sbs.apply(current_turn.point); bool result = analyze_cluster_intersection(turn_index, op_index, sbs); return result; } inline void change_index_for_self_turn(signed_size_type& to_vertex_index, turn_type const& start_turn, turn_operation_type const& start_op, int start_op_index) const { if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_buffer && OverlayType != overlay_dissolve)) { return; } const bool allow_uu = OverlayType != overlay_buffer; // It travels to itself, can happen. If this is a buffer, it can // sometimes travel to itself in the following configuration: // // +---->--+ // | | // | +---*----+ *: one turn, with segment index 2/7 // | | | | // | +---C | C: closing point (start/end) // | | // +------------+ // // If it starts on segment 2 and travels to itself on segment 2, that // should be corrected to 7 because that is the shortest path // // Also a uu turn (touching with another buffered ring) might have this // apparent configuration, but there it should // always travel the whole ring turn_operation_type const& other_op = start_turn.operations[1 - start_op_index]; bool const correct = (allow_uu || ! start_turn.both(operation_union)) && start_op.seg_id.source_index == other_op.seg_id.source_index && start_op.seg_id.multi_index == other_op.seg_id.multi_index && start_op.seg_id.ring_index == other_op.seg_id.ring_index && start_op.seg_id.segment_index == to_vertex_index; #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) std::cout << " WARNING: self-buffer " << " correct=" << correct << " turn=" << operation_char(start_turn.operations[0].operation) << operation_char(start_turn.operations[1].operation) << " start=" << start_op.seg_id.segment_index << " from=" << to_vertex_index << " to=" << other_op.enriched.travels_to_vertex_index << std::endl; #endif if (correct) { to_vertex_index = other_op.enriched.travels_to_vertex_index; } } bool select_turn_from_enriched(signed_size_type& turn_index, segment_identifier& previous_seg_id, signed_size_type& to_vertex_index, signed_size_type start_turn_index, int start_op_index, turn_type const& previous_turn, turn_operation_type const& previous_op, bool is_start) const { to_vertex_index = -1; if (previous_op.enriched.next_ip_index < 0) { // There is no next IP on this segment if (previous_op.enriched.travels_to_vertex_index < 0 || previous_op.enriched.travels_to_ip_index < 0) { return false; } to_vertex_index = previous_op.enriched.travels_to_vertex_index; if (is_start && previous_op.enriched.travels_to_ip_index == start_turn_index) { change_index_for_self_turn(to_vertex_index, previous_turn, previous_op, start_op_index); } turn_index = previous_op.enriched.travels_to_ip_index; previous_seg_id = previous_op.seg_id; } else { // Take the next IP on this segment turn_index = previous_op.enriched.next_ip_index; previous_seg_id = previous_op.seg_id; } return true; } bool select_turn(signed_size_type start_turn_index, int start_op_index, signed_size_type& turn_index, int& op_index, int previous_op_index, signed_size_type previous_turn_index, segment_identifier const& previous_seg_id, bool is_start, bool has_points) { turn_type const& current_turn = m_turns[turn_index]; if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)) { if (has_points) { bool const back_at_start_cluster = current_turn.is_clustered() && m_turns[start_turn_index].cluster_id == current_turn.cluster_id; if (turn_index == start_turn_index || back_at_start_cluster) { // Intersection can always be finished if returning turn_index = start_turn_index; op_index = start_op_index; return true; } } if (! current_turn.is_clustered() && current_turn.both(operation_intersection)) { if (analyze_ii_intersection(turn_index, op_index, current_turn, previous_seg_id)) { return true; } } } if (current_turn.is_clustered()) { if (! select_turn_from_cluster(turn_index, op_index, start_turn_index, start_op_index, previous_seg_id)) { return false; } if (is_start && turn_index == previous_turn_index) { op_index = previous_op_index; } } else { op_index = starting_operation_index(current_turn); if (op_index == -1) { if (both_finished(current_turn)) { return false; } if (! select_operation(current_turn, turn_index, start_turn_index, previous_seg_id, op_index)) { return false; } } } return true; } private : Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; Turns& m_turns; Clusters const& m_clusters; RobustPolicy const& m_robust_policy; SideStrategy m_strategy; Visitor& m_visitor; }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_HPP detail/overlay/segment_as_subrange.hpp 0000644 00000002720 15125631657 0014227 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2019-2019 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP #include <cstddef> #include <map> #include <boost/geometry/core/access.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename Segment> struct segment_as_subrange { segment_as_subrange(Segment const& s) : m_segment(s) { geometry::set<0>(m_p1, geometry::get<0, 0>(m_segment)); geometry::set<1>(m_p1, geometry::get<0, 1>(m_segment)); geometry::set<0>(m_p2, geometry::get<1, 0>(m_segment)); geometry::set<1>(m_p2, geometry::get<1, 1>(m_segment)); } typedef typename geometry::point_type<Segment>::type point_type; point_type const& at(std::size_t index) const { return index == 0 ? m_p1 : m_p2; } static inline bool is_last_segment() { return true; } point_type m_p1, m_p2; Segment const& m_segment; }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP detail/overlay/range_in_geometry.hpp 0000644 00000011663 15125631657 0013717 0 ustar 00 // Boost.Geometry // Copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/iterators/point_iterator.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < typename Geometry, typename Tag = typename geometry::tag<Geometry>::type > struct points_range { typedef geometry::point_iterator<Geometry const> iterator_type; explicit points_range(Geometry const& geometry) : m_geometry(geometry) {} iterator_type begin() const { return geometry::points_begin(m_geometry); } iterator_type end() const { return geometry::points_end(m_geometry); } Geometry const& m_geometry; }; // Specialized because point_iterator doesn't support boxes template <typename Box> struct points_range<Box, box_tag> { typedef typename geometry::point_type<Box>::type point_type; typedef const point_type * iterator_type; explicit points_range(Box const& box) { detail::assign_box_corners(box, m_corners[0], m_corners[1], m_corners[2], m_corners[3]); } iterator_type begin() const { return m_corners; } iterator_type end() const { return m_corners + 4; } point_type m_corners[4]; }; template < typename Geometry, typename Tag = typename geometry::tag<Geometry>::type > struct point_in_geometry_helper { template <typename Point, typename Strategy> static inline int apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { return detail::within::point_in_geometry(point, geometry, strategy); } }; // Specialized because point_in_geometry doesn't support Boxes template <typename Box> struct point_in_geometry_helper<Box, box_tag> { template <typename Point, typename Strategy> static inline int apply(Point const& point, Box const& box, Strategy const&) { return geometry::covered_by(point, box) ? 1 : -1; } }; // This function returns // when it finds a point of geometry1 inside or outside geometry2 template <typename Geometry1, typename Geometry2, typename Strategy> static inline int range_in_geometry(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy, bool skip_first = false) { int result = 0; points_range<Geometry1> points(geometry1); typedef typename points_range<Geometry1>::iterator_type iterator_type; iterator_type const end = points.end(); iterator_type it = points.begin(); if (it == end) { return result; } else if (skip_first) { ++it; } typename Strategy::template point_in_geometry_strategy < Geometry1, Geometry2 >::type const in_strategy = strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>(); for ( ; it != end; ++it) { result = point_in_geometry_helper<Geometry2>::apply(*it, geometry2, in_strategy); if (result != 0) { return result; } } // all points contained entirely by the boundary return result; } // This function returns if first_point1 is inside or outside geometry2 or // when it finds a point of geometry1 inside or outside geometry2 template <typename Point1, typename Geometry1, typename Geometry2, typename Strategy> inline int range_in_geometry(Point1 const& first_point1, Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // check a point on border of geometry1 first int result = point_in_geometry_helper<Geometry2>::apply(first_point1, geometry2, strategy.template get_point_in_geometry_strategy<Point1, Geometry2>()); if (result == 0) { // if a point is on boundary of geometry2 // check points of geometry1 until point inside/outside is found // NOTE: skip first point because it should be already tested above result = range_in_geometry(geometry1, geometry2, strategy, true); } return result; } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP detail/overlay/append_no_duplicates.hpp 0000644 00000004077 15125631657 0014403 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018-2020. // Modifications copyright (c) 2018-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Range, typename Point> inline void append_with_duplicates(Range& range, Point const& point) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION std::cout << " add: (" << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" << std::endl; #endif geometry::append(range, point); } template <typename Range, typename Point, typename EqPPStrategy> inline void append_no_duplicates(Range& range, Point const& point, EqPPStrategy const& strategy) { if ( boost::empty(range) || ! geometry::detail::equals::equals_point_point(geometry::range::back(range), point, strategy) ) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION std::cout << " add: (" << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" << std::endl; #endif geometry::append(range, point); } } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP detail/overlay/select_rings.hpp 0000644 00000030231 15125631657 0012673 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP #include <map> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp> #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { struct ring_turn_info { bool has_traversed_turn; bool has_blocked_turn; bool within_other; ring_turn_info() : has_traversed_turn(false) , has_blocked_turn(false) , within_other(false) {} }; namespace dispatch { template <typename Tag, typename Geometry> struct select_rings {}; template <typename Box> struct select_rings<box_tag, Box> { template <typename Geometry, typename RingPropertyMap, typename AreaStrategy> static inline void apply(Box const& box, Geometry const& , ring_identifier const& id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy); } template <typename RingPropertyMap, typename AreaStrategy> static inline void apply(Box const& box, ring_identifier const& id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy); } }; template <typename Ring> struct select_rings<ring_tag, Ring> { template <typename Geometry, typename RingPropertyMap, typename AreaStrategy> static inline void apply(Ring const& ring, Geometry const& , ring_identifier const& id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { if (boost::size(ring) > 0) { ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy); } } template <typename RingPropertyMap, typename AreaStrategy> static inline void apply(Ring const& ring, ring_identifier const& id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { if (boost::size(ring) > 0) { ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy); } } }; template <typename Polygon> struct select_rings<polygon_tag, Polygon> { template <typename Geometry, typename RingPropertyMap, typename AreaStrategy> static inline void apply(Polygon const& polygon, Geometry const& geometry, ring_identifier id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef select_rings<ring_tag, ring_type> per_ring; per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy); typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; per_ring::apply(*it, geometry, id, ring_properties, strategy); } } template <typename RingPropertyMap, typename AreaStrategy> static inline void apply(Polygon const& polygon, ring_identifier id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef select_rings<ring_tag, ring_type> per_ring; per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy); typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { id.ring_index++; per_ring::apply(*it, id, ring_properties, strategy); } } }; template <typename Multi> struct select_rings<multi_polygon_tag, Multi> { template <typename Geometry, typename RingPropertyMap, typename AreaStrategy> static inline void apply(Multi const& multi, Geometry const& geometry, ring_identifier id, RingPropertyMap& ring_properties, AreaStrategy const& strategy) { typedef typename boost::range_iterator < Multi const >::type iterator_type; typedef select_rings<polygon_tag, typename boost::range_value<Multi>::type> per_polygon; id.multi_index = 0; for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it) { id.ring_index = -1; per_polygon::apply(*it, geometry, id, ring_properties, strategy); id.multi_index++; } } }; } // namespace dispatch template<overlay_type OverlayType> struct decide { // Default implementation (union, inflate, deflate, dissolve) static bool include(ring_identifier const& , ring_turn_info const& info) { return ! info.within_other; } static bool reversed(ring_identifier const& , ring_turn_info const& ) { return false; } }; template<> struct decide<overlay_difference> { static bool include(ring_identifier const& id, ring_turn_info const& info) { // Difference: A - B // If this is A (source_index=0), then the ring is inside B // If this is B (source_index=1), then the ring is NOT inside A // If this is A and the ring is within the other geometry, // then we should NOT include it. // If this is B then we SHOULD include it. return id.source_index == 0 ? ! info.within_other : info.within_other; } static bool reversed(ring_identifier const& id, ring_turn_info const& info) { // Difference: A - B // If this is B, and the ring is included, it should be reversed afterwards return id.source_index == 1 && include(id, info); } }; template<> struct decide<overlay_intersection> { static bool include(ring_identifier const& , ring_turn_info const& info) { return info.within_other; } static bool reversed(ring_identifier const& , ring_turn_info const& ) { return false; } }; template < overlay_type OverlayType, typename Geometry1, typename Geometry2, typename TurnInfoMap, typename RingPropertyMap, typename Strategy > inline void update_ring_selection(Geometry1 const& geometry1, Geometry2 const& geometry2, TurnInfoMap const& turn_info_map, RingPropertyMap const& all_ring_properties, RingPropertyMap& selected_ring_properties, Strategy const& strategy) { selected_ring_properties.clear(); for (typename RingPropertyMap::const_iterator it = boost::begin(all_ring_properties); it != boost::end(all_ring_properties); ++it) { ring_identifier const& id = it->first; ring_turn_info info; typename TurnInfoMap::const_iterator tcit = turn_info_map.find(id); if (tcit != turn_info_map.end()) { info = tcit->second; // Copy by value } if (info.has_traversed_turn || info.has_blocked_turn) { // This turn is traversed or blocked, // don't include the original ring continue; } // Check if the ring is within the other geometry, by taking // a point lying on the ring switch(id.source_index) { // within case 0 : info.within_other = range_in_geometry(it->second.point, geometry1, geometry2, strategy) > 0; break; case 1 : info.within_other = range_in_geometry(it->second.point, geometry2, geometry1, strategy) > 0; break; } if (decide<OverlayType>::include(id, info)) { typename RingPropertyMap::mapped_type properties = it->second; // Copy by value properties.reversed = decide<OverlayType>::reversed(id, info); selected_ring_properties[id] = properties; } } } /*! \brief The function select_rings select rings based on the overlay-type (union,intersection) */ template < overlay_type OverlayType, typename Geometry1, typename Geometry2, typename RingTurnInfoMap, typename RingPropertyMap, typename Strategy > inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2, RingTurnInfoMap const& turn_info_per_ring, RingPropertyMap& selected_ring_properties, Strategy const& strategy) { typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; RingPropertyMap all_ring_properties; dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2, ring_identifier(0, -1, -1), all_ring_properties, strategy.template get_area_strategy<point1_type>()); dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1, ring_identifier(1, -1, -1), all_ring_properties, strategy.template get_area_strategy<point2_type>()); update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring, all_ring_properties, selected_ring_properties, strategy); } template < overlay_type OverlayType, typename Geometry, typename RingTurnInfoMap, typename RingPropertyMap, typename Strategy > inline void select_rings(Geometry const& geometry, RingTurnInfoMap const& turn_info_per_ring, RingPropertyMap& selected_ring_properties, Strategy const& strategy) { typedef typename geometry::tag<Geometry>::type tag; typedef typename geometry::point_type<Geometry>::type point_type; RingPropertyMap all_ring_properties; dispatch::select_rings<tag, Geometry>::apply(geometry, ring_identifier(0, -1, -1), all_ring_properties, strategy.template get_area_strategy<point_type>()); update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring, all_ring_properties, selected_ring_properties, strategy); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP detail/overlay/get_turns.hpp 0000644 00000120704 15125631657 0012231 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP #include <cstddef> #include <map> #include <boost/array.hpp> #include <boost/concept_check.hpp> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/box_box.hpp> #include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/algorithms/detail/sections/range_by_section.hpp> #include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp> #include <boost/geometry/algorithms/detail/sections/section_functions.hpp> #include <boost/geometry/algorithms/detail/sections/sectionalize.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/box.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/strategies/intersection_strategies.hpp> #include <boost/geometry/strategies/intersection_result.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/type_traits.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> #include <boost/geometry/views/detail/range_type.hpp> #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION # include <sstream> # include <boost/geometry/io/dsv/write.hpp> #endif namespace boost { namespace geometry { // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace get_turns { struct no_interrupt_policy { static bool const enabled = false; // variable required by self_get_turn_points::get_turns static bool const has_intersections = false; template <typename Range> static inline bool apply(Range const&) { return false; } }; template < bool IsAreal, typename Section, typename Point, typename CircularIterator, typename IntersectionStrategy, typename RobustPolicy > struct unique_sub_range_from_section { typedef Point point_type; unique_sub_range_from_section(Section const& section, signed_size_type index, CircularIterator circular_iterator, Point const& previous, Point const& current, RobustPolicy const& robust_policy) : m_section(section) , m_index(index) , m_previous_point(previous) , m_current_point(current) , m_circular_iterator(circular_iterator) , m_point_retrieved(false) , m_robust_policy(robust_policy) { } inline bool is_first_segment() const { return !IsAreal && m_section.is_non_duplicate_first && m_index == m_section.begin_index; } inline bool is_last_segment() const { return size() == 2u; } inline std::size_t size() const { return IsAreal ? 3 : m_section.is_non_duplicate_last && m_index + 1 >= m_section.end_index ? 2 : 3; } inline Point const& at(std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < size()); switch (index) { case 0 : return m_previous_point; case 1 : return m_current_point; case 2 : return get_next_point(); default : return m_previous_point; } } private : inline Point const& get_next_point() const { if (! m_point_retrieved) { advance_to_non_duplicate_next(m_current_point, m_circular_iterator); m_point = *m_circular_iterator; m_point_retrieved = true; } return m_point; } inline void advance_to_non_duplicate_next(Point const& current, CircularIterator& circular_iterator) const { typedef typename IntersectionStrategy::point_in_point_strategy_type disjoint_strategy_type; typedef typename robust_point_type<Point, RobustPolicy>::type robust_point_type; robust_point_type current_robust_point; robust_point_type next_robust_point; geometry::recalculate(current_robust_point, current, m_robust_policy); geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy); // To see where the next segments bend to, in case of touch/intersections // on end points, we need (in case of degenerate/duplicate points) an extra // iterator which moves to the REAL next point, so non duplicate. // This needs an extra comparison (disjoint). // (Note that within sections, non duplicate points are already asserted, // by the sectionalize process). // So advance to the "non duplicate next" // (the check is defensive, to avoid endless loops) std::size_t check = 0; while(! detail::disjoint::disjoint_point_point ( current_robust_point, next_robust_point, disjoint_strategy_type() ) && check++ < m_section.range_count) { circular_iterator++; geometry::recalculate(next_robust_point, *circular_iterator, m_robust_policy); } } Section const& m_section; signed_size_type m_index; Point const& m_previous_point; Point const& m_current_point; mutable CircularIterator m_circular_iterator; mutable Point m_point; mutable bool m_point_retrieved; RobustPolicy m_robust_policy; }; template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, typename Section1, typename Section2, typename TurnPolicy > class get_turns_in_sections { typedef typename closeable_view < typename range_type<Geometry1>::type const, closure<Geometry1>::value >::type cview_type1; typedef typename closeable_view < typename range_type<Geometry2>::type const, closure<Geometry2>::value >::type cview_type2; typedef typename reversible_view < cview_type1 const, Reverse1 ? iterate_reverse : iterate_forward >::type view_type1; typedef typename reversible_view < cview_type2 const, Reverse2 ? iterate_reverse : iterate_forward >::type view_type2; typedef typename boost::range_iterator < view_type1 const >::type range1_iterator; typedef typename boost::range_iterator < view_type2 const >::type range2_iterator; typedef ever_circling_iterator<range1_iterator> circular1_iterator; typedef ever_circling_iterator<range2_iterator> circular2_iterator; template <typename Geometry, typename Section> static inline bool adjacent(Section const& section, signed_size_type index1, signed_size_type index2) { // About n-2: // (square: range_count=5, indices 0,1,2,3 // -> 0-3 are adjacent, don't check on intersections) // Also tested for open polygons, and/or duplicates // About first condition: will be optimized by compiler (static) // It checks if it is areal (box, ring, (multi)polygon) signed_size_type const n = static_cast<signed_size_type>(section.range_count); boost::ignore_unused(n, index1, index2); return util::is_areal<Geometry>::value && index1 == 0 && index2 >= n - 2 ; } public : // Returns true if terminated, false if interrupted template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline bool apply( int source_id1, Geometry1 const& geometry1, Section1 const& sec1, int source_id2, Geometry2 const& geometry2, Section2 const& sec2, bool skip_larger, bool skip_adjacent, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { boost::ignore_unused(interrupt_policy); static bool const areal1 = util::is_areal<Geometry1>::value; static bool const areal2 = util::is_areal<Geometry2>::value; if ((sec1.duplicate && (sec1.count + 1) < sec1.range_count) || (sec2.duplicate && (sec2.count + 1) < sec2.range_count)) { // Skip sections containig only duplicates. // They are still important (can indicate non-disjointness) // but they will be found processing adjacent sections. // Do NOT skip if they are the ONLY section return true; } cview_type1 cview1(range_by_section(geometry1, sec1)); cview_type2 cview2(range_by_section(geometry2, sec2)); view_type1 view1(cview1); view_type2 view2(cview2); range1_iterator begin_range_1 = boost::begin(view1); range1_iterator end_range_1 = boost::end(view1); range2_iterator begin_range_2 = boost::begin(view2); range2_iterator end_range_2 = boost::end(view2); int const dir1 = sec1.directions[0]; int const dir2 = sec2.directions[0]; signed_size_type index1 = sec1.begin_index; signed_size_type ndi1 = sec1.non_duplicate_index; range1_iterator prev1, it1, end1; get_start_point_iterator(sec1, view1, prev1, it1, end1, index1, ndi1, dir1, sec2.bounding_box, robust_policy); // We need a circular iterator because it might run through the closing point. // One circle is actually enough but this one is just convenient. ever_circling_iterator<range1_iterator> next1(begin_range_1, end_range_1, it1, true); next1++; // Walk through section and stop if we exceed the other box // section 2: [--------------] // section 1: |----|---|---|---|---| for (prev1 = it1++, next1++; it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy); ++prev1, ++it1, ++index1, ++next1, ++ndi1) { unique_sub_range_from_section < areal1, Section1, point1_type, circular1_iterator, IntersectionStrategy, RobustPolicy > unique_sub_range1(sec1, index1, circular1_iterator(begin_range_1, end_range_1, next1, true), *prev1, *it1, robust_policy); signed_size_type index2 = sec2.begin_index; signed_size_type ndi2 = sec2.non_duplicate_index; range2_iterator prev2, it2, end2; get_start_point_iterator(sec2, view2, prev2, it2, end2, index2, ndi2, dir2, sec1.bounding_box, robust_policy); ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true); next2++; for (prev2 = it2++, next2++; it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy); ++prev2, ++it2, ++index2, ++next2, ++ndi2) { bool skip = false; if (source_id1 == source_id2 && sec1.ring_id.multi_index == sec2.ring_id.multi_index && sec1.ring_id.ring_index == sec2.ring_id.ring_index) { // Sources and rings are the same if (skip_larger && index1 >= index2) { // Skip to avoid getting all intersections twice skip = true; } else if (skip_adjacent) { // In some cases (dissolve, has_self_intersections) // neighbouring segments should be checked // (for example to detect spikes properly) // skip if it is a neighbouring segment. // (including, for areas, first-last segment // and two segments with one or more degenerate/duplicate // (zero-length) segments in between) skip = ndi2 == ndi1 + 1 || adjacent<Geometry1>(sec1, index1, index2); } } if (! skip) { unique_sub_range_from_section < areal2, Section2, point2_type, circular2_iterator, IntersectionStrategy, RobustPolicy > unique_sub_range2(sec2, index2, circular2_iterator(begin_range_2, end_range_2, next2), *prev2, *it2, robust_policy); typedef typename boost::range_value<Turns>::type turn_info; turn_info ti; ti.operations[0].seg_id = segment_identifier(source_id1, sec1.ring_id.multi_index, sec1.ring_id.ring_index, index1); ti.operations[1].seg_id = segment_identifier(source_id2, sec2.ring_id.multi_index, sec2.ring_id.ring_index, index2); std::size_t const size_before = boost::size(turns); TurnPolicy::apply(unique_sub_range1, unique_sub_range2, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) { if (interrupt_policy.apply( std::make_pair(range::pos(turns, size_before), boost::end(turns)))) { return false; } } } } } return true; } private : typedef typename geometry::point_type<Geometry1>::type point1_type; typedef typename geometry::point_type<Geometry2>::type point2_type; // It is NOT possible to have section-iterators here // because of the logistics of "index" (the section-iterator automatically // skips to the begin-point, we loose the index or have to recalculate it) // So we mimic it here template <typename Range, typename Section, typename Box, typename RobustPolicy> static inline void get_start_point_iterator(Section const& section, Range const& range, typename boost::range_iterator<Range const>::type& it, typename boost::range_iterator<Range const>::type& prev, typename boost::range_iterator<Range const>::type& end, signed_size_type& index, signed_size_type& ndi, int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy) { it = boost::begin(range) + section.begin_index; end = boost::begin(range) + section.end_index + 1; // Mimic section-iterator: // Skip to point such that section interects other box prev = it++; for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy); prev = it++, index++, ndi++) {} // Go back one step because we want to start completely preceding it = prev; } }; template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, typename TurnPolicy, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > struct section_visitor { int m_source_id1; Geometry1 const& m_geometry1; int m_source_id2; Geometry2 const& m_geometry2; IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; section_visitor(int id1, Geometry1 const& g1, int id2, Geometry2 const& g2, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& ip) : m_source_id1(id1), m_geometry1(g1) , m_source_id2(id2), m_geometry2(g2) , m_intersection_strategy(intersection_strategy) , m_rescale_policy(robust_policy) , m_turns(turns) , m_interrupt_policy(ip) {} template <typename Section> inline bool apply(Section const& sec1, Section const& sec2) { if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box, m_intersection_strategy.get_disjoint_box_box_strategy())) { // false if interrupted return get_turns_in_sections < Geometry1, Geometry2, Reverse1, Reverse2, Section, Section, TurnPolicy >::apply(m_source_id1, m_geometry1, sec1, m_source_id2, m_geometry2, sec2, false, false, m_intersection_strategy, m_rescale_policy, m_turns, m_interrupt_policy); } return true; } }; template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, typename TurnPolicy > class get_turns_generic { public: template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Geometry1 const& geometry1, int source_id2, Geometry2 const& geometry2, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { // First create monotonic sections... typedef typename boost::range_value<Turns>::type ip_type; typedef typename ip_type::point_type point_type; typedef model::box < typename geometry::robust_point_type < point_type, RobustPolicy >::type > box_type; typedef geometry::sections<box_type, 2> sections_type; sections_type sec1, sec2; typedef std::integer_sequence<std::size_t, 0, 1> dimensions; typename IntersectionStrategy::envelope_strategy_type const envelope_strategy = intersection_strategy.get_envelope_strategy(); typename IntersectionStrategy::expand_strategy_type const expand_strategy = intersection_strategy.get_expand_strategy(); geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy, sec1, envelope_strategy, expand_strategy, 0); geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy, sec2, envelope_strategy, expand_strategy, 1); // ... and then partition them, intersecting overlapping sections in visitor method section_visitor < Geometry1, Geometry2, Reverse1, Reverse2, TurnPolicy, IntersectionStrategy, RobustPolicy, Turns, InterruptPolicy > visitor(source_id1, geometry1, source_id2, geometry2, intersection_strategy, robust_policy, turns, interrupt_policy); typedef detail::section::get_section_box < typename IntersectionStrategy::expand_box_strategy_type > get_section_box_type; typedef detail::section::overlaps_section_box < typename IntersectionStrategy::disjoint_box_box_strategy_type > overlaps_section_box_type; geometry::partition < box_type >::apply(sec1, sec2, visitor, get_section_box_type(), overlaps_section_box_type()); } }; // Get turns for a range with a box, following Cohen-Sutherland (cs) approach template < typename Range, typename Box, bool ReverseRange, bool ReverseBox, typename TurnPolicy > struct get_turns_cs { typedef typename geometry::point_type<Range>::type range_point_type; typedef typename geometry::point_type<Box>::type box_point_type; typedef boost::array<box_point_type, 4> box_array; typedef typename closeable_view < Range const, closure<Range>::value >::type cview_type; typedef typename reversible_view < cview_type const, ReverseRange ? iterate_reverse : iterate_forward >::type view_type; typedef typename boost::range_iterator < view_type const >::type iterator_type; struct unique_sub_range_from_box_policy { typedef box_point_type point_type; unique_sub_range_from_box_policy(box_array const& box) : m_box(box) , m_index(0) {} static inline bool is_first_segment() { return false; } static inline bool is_last_segment() { return false; } static inline std::size_t size() { return 4; } inline box_point_type const& at(std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < size()); return m_box[(m_index + index) % 4]; } inline void next() { m_index++; } private : box_array const& m_box; std::size_t m_index; }; struct unique_sub_range_from_view_policy { typedef range_point_type point_type; unique_sub_range_from_view_policy(view_type const& view, point_type const& pi, point_type const& pj, iterator_type it) : m_view(view) , m_pi(pi) , m_pj(pj) , m_circular_iterator(boost::begin(view), boost::end(view), it, true) { ++m_circular_iterator; } static inline bool is_first_segment() { return false; } static inline bool is_last_segment() { return false; } static inline std::size_t size() { return 3; } inline point_type const& at(std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < size()); switch (index) { case 0 : return m_pi; case 1 : return m_pj; case 2 : return *m_circular_iterator; default : return m_pi; } } private : view_type const& m_view; point_type const& m_pi; point_type const& m_pj; ever_circling_iterator<iterator_type> m_circular_iterator; }; template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Range const& range, int source_id2, Box const& box, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, signed_size_type multi_index = -1, signed_size_type ring_index = -1) { if ( boost::size(range) <= 1) { return; } box_array box_points; assign_box_corners_oriented<ReverseBox>(box, box_points); cview_type cview(range); view_type view(cview); // TODO: in this code, possible duplicate points are not yet taken // into account (not in the iterator, nor in the retrieve policy) iterator_type it = boost::begin(view); //bool first = true; //char previous_side[2] = {0, 0}; signed_size_type index = 0; for (iterator_type prev = it++; it != boost::end(view); prev = it++, index++) { segment_identifier seg_id(source_id1, multi_index, ring_index, index); unique_sub_range_from_view_policy view_unique_sub_range(view, *prev, *it, it); /*if (first) { previous_side[0] = get_side<0>(box, *prev); previous_side[1] = get_side<1>(box, *prev); } char current_side[2]; current_side[0] = get_side<0>(box, *it); current_side[1] = get_side<1>(box, *it); // There can NOT be intersections if // 1) EITHER the two points are lying on one side of the box (! 0 && the same) // 2) OR same in Y-direction // 3) OR all points are inside the box (0) if (! ( (current_side[0] != 0 && current_side[0] == previous_side[0]) || (current_side[1] != 0 && current_side[1] == previous_side[1]) || (current_side[0] == 0 && current_side[1] == 0 && previous_side[0] == 0 && previous_side[1] == 0) ) )*/ if (true) { get_turns_with_box(seg_id, source_id2, view_unique_sub_range, box_points, intersection_strategy, robust_policy, turns, interrupt_policy); // Future performance enhancement: // return if told by the interrupt policy } } } private: template<std::size_t Index, typename Point> static inline int get_side(Box const& box, Point const& point) { // Inside -> 0 // Outside -> -1 (left/below) or 1 (right/above) // On border -> -2 (left/lower) or 2 (right/upper) // The only purpose of the value is to not be the same, // and to denote if it is inside (0) typename coordinate_type<Point>::type const& c = get<Index>(point); typename coordinate_type<Box>::type const& left = get<min_corner, Index>(box); typename coordinate_type<Box>::type const& right = get<max_corner, Index>(box); if (geometry::math::equals(c, left)) return -2; else if (geometry::math::equals(c, right)) return 2; else if (c < left) return -1; else if (c > right) return 1; else return 0; } template < typename IntersectionStrategy, typename Turns, typename InterruptPolicy, typename RobustPolicy > static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2, unique_sub_range_from_view_policy const& range_unique_sub_range, box_array const& box, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, // Output Turns& turns, InterruptPolicy& interrupt_policy) { boost::ignore_unused(interrupt_policy); // Depending on code some relations can be left out typedef typename boost::range_value<Turns>::type turn_info; turn_info ti; ti.operations[0].seg_id = seg_id; unique_sub_range_from_box_policy box_unique_sub_range(box); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0); TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1); box_unique_sub_range.next(); TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2); box_unique_sub_range.next(); TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3); box_unique_sub_range.next(); TurnPolicy::apply(range_unique_sub_range, box_unique_sub_range, ti, intersection_strategy, robust_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) { interrupt_policy.apply(turns); } } }; template < typename Polygon, typename Box, bool Reverse, bool ReverseBox, typename TurnPolicy > struct get_turns_polygon_cs { template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Polygon const& polygon, int source_id2, Box const& box, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, signed_size_type multi_index = -1) { typedef typename geometry::ring_type<Polygon>::type ring_type; typedef detail::get_turns::get_turns_cs < ring_type, Box, Reverse, ReverseBox, TurnPolicy > intersector_type; intersector_type::apply( source_id1, geometry::exterior_ring(polygon), source_id2, box, intersection_strategy, robust_policy, turns, interrupt_policy, multi_index, -1); signed_size_type i = 0; typename interior_return_type<Polygon const>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it, ++i) { intersector_type::apply( source_id1, *it, source_id2, box, intersection_strategy, robust_policy, turns, interrupt_policy, multi_index, i); } } }; template < typename Multi, typename Box, bool Reverse, bool ReverseBox, typename TurnPolicy > struct get_turns_multi_polygon_cs { template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply( int source_id1, Multi const& multi, int source_id2, Box const& box, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { typedef typename boost::range_iterator < Multi const >::type iterator_type; signed_size_type i = 0; for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it, ++i) { // Call its single version get_turns_polygon_cs < typename boost::range_value<Multi>::type, Box, Reverse, ReverseBox, TurnPolicy >::apply(source_id1, *it, source_id2, box, intersection_strategy, robust_policy, turns, interrupt_policy, i); } } }; // GET_TURN_INFO_TYPE template <typename Geometry> struct topological_tag_base { typedef typename tag_cast<typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag>::type type; }; template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type> struct get_turn_info_type : overlay::get_turn_info<AssignPolicy> {}; template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2> struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag> : overlay::get_turn_info_linear_linear<AssignPolicy> {}; template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2> struct get_turn_info_type<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, areal_tag> : overlay::get_turn_info_linear_areal<AssignPolicy> {}; template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, typename TagBase1 = typename topological_tag_base<Geometry1>::type, typename TagBase2 = typename topological_tag_base<Geometry2>::type> struct turn_operation_type { typedef overlay::turn_operation<typename point_type<Geometry1>::type, SegmentRatio> type; }; template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2> struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, linear_tag> { typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type; }; template <typename Geometry1, typename Geometry2, typename SegmentRatio, typename Tag1, typename Tag2> struct turn_operation_type<Geometry1, Geometry2, SegmentRatio, Tag1, Tag2, linear_tag, areal_tag> { typedef overlay::turn_operation_linear<typename point_type<Geometry1>::type, SegmentRatio> type; }; }} // namespace detail::get_turns #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // Because this is "detail" method, and most implementations will use "generic", // we take the freedom to derive it from "generic". template < typename GeometryTag1, typename GeometryTag2, typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, typename TurnPolicy > struct get_turns : detail::get_turns::get_turns_generic < Geometry1, Geometry2, Reverse1, Reverse2, TurnPolicy > {}; template < typename Polygon, typename Box, bool ReversePolygon, bool ReverseBox, typename TurnPolicy > struct get_turns < polygon_tag, box_tag, Polygon, Box, ReversePolygon, ReverseBox, TurnPolicy > : detail::get_turns::get_turns_polygon_cs < Polygon, Box, ReversePolygon, ReverseBox, TurnPolicy > {}; template < typename Ring, typename Box, bool ReverseRing, bool ReverseBox, typename TurnPolicy > struct get_turns < ring_tag, box_tag, Ring, Box, ReverseRing, ReverseBox, TurnPolicy > : detail::get_turns::get_turns_cs < Ring, Box, ReverseRing, ReverseBox, TurnPolicy > {}; template < typename MultiPolygon, typename Box, bool ReverseMultiPolygon, bool ReverseBox, typename TurnPolicy > struct get_turns < multi_polygon_tag, box_tag, MultiPolygon, Box, ReverseMultiPolygon, ReverseBox, TurnPolicy > : detail::get_turns::get_turns_multi_polygon_cs < MultiPolygon, Box, ReverseMultiPolygon, ReverseBox, TurnPolicy > {}; template < typename GeometryTag1, typename GeometryTag2, typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, typename TurnPolicy > struct get_turns_reversed { template <typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy> static inline void apply(int source_id1, Geometry1 const& g1, int source_id2, Geometry2 const& g2, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { get_turns < GeometryTag2, GeometryTag1, Geometry2, Geometry1, Reverse2, Reverse1, TurnPolicy >::apply(source_id2, g2, source_id1, g1, intersection_strategy, robust_policy, turns, interrupt_policy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief \brief_calc2{turn points} \ingroup overlay \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s) \param geometry1 \param_geometry \param geometry2 \param_geometry \param intersection_strategy segments intersection strategy \param robust_policy policy to handle robustness issues \param turns container which will contain turn points \param interrupt_policy policy determining if process is stopped when intersection is found */ template < bool Reverse1, bool Reverse2, typename AssignPolicy, typename Geometry1, typename Geometry2, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void get_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>(); typedef detail::overlay::get_turn_info<AssignPolicy> TurnPolicy; //typedef detail::get_turns::get_turn_info_type<Geometry1, Geometry2, AssignPolicy> TurnPolicy; std::conditional_t < reverse_dispatch<Geometry1, Geometry2>::type::value, dispatch::get_turns_reversed < typename tag<Geometry1>::type, typename tag<Geometry2>::type, Geometry1, Geometry2, Reverse1, Reverse2, TurnPolicy >, dispatch::get_turns < typename tag<Geometry1>::type, typename tag<Geometry2>::type, Geometry1, Geometry2, Reverse1, Reverse2, TurnPolicy > >::apply(0, geometry1, 1, geometry2, intersection_strategy, robust_policy, turns, interrupt_policy); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP detail/overlay/needs_self_turns.hpp 0000644 00000004124 15125631657 0013556 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017-2017 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP #include <boost/range/begin.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/num_interior_rings.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct needs_self_turns { }; template <typename Geometry> struct needs_self_turns<Geometry, box_tag> { static inline bool apply(Geometry const&) { return false; } }; template <typename Geometry> struct needs_self_turns<Geometry, ring_tag> { static inline bool apply(Geometry const&) { return false; } }; template <typename Geometry> struct needs_self_turns<Geometry, polygon_tag> { static inline bool apply(Geometry const& polygon) { return geometry::num_interior_rings(polygon) > 0; } }; template <typename Geometry> struct needs_self_turns<Geometry, multi_polygon_tag> { static inline bool apply(Geometry const& multi) { typedef typename boost::range_value<Geometry>::type polygon_type; std::size_t const n = boost::size(multi); return n > 1 || (n == 1 && needs_self_turns<polygon_type> ::apply(*boost::begin(multi))); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_NEEDS_SELF_TURNS_HPP detail/overlay/intersection_insert.hpp 0000644 00000134451 15125631657 0014315 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP #include <cstddef> #include <deque> #include <type_traits> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/detail/overlay/clip_linestring.hpp> #include <boost/geometry/algorithms/detail/overlay/follow.hpp> #include <boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp> #include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_areal.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/policies/robustness/rescale_policy_tags.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/views/segment_view.hpp> #include <boost/geometry/views/detail/boundary_view.hpp> #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) #include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> #include <boost/geometry/io/wkt/wkt.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template <typename PointOut> struct intersection_segment_segment_point { template < typename Segment1, typename Segment2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Segment1 const& segment1, Segment2 const& segment2, RobustPolicy const& , OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef typename point_type<PointOut>::type point_type; // Get the intersection point (or two points) typedef segment_intersection_points<point_type> intersection_return_type; typedef policies::relate::segments_intersection_points < intersection_return_type > policy_type; detail::segment_as_subrange<Segment1> sub_range1(segment1); detail::segment_as_subrange<Segment2> sub_range2(segment2); intersection_return_type is = strategy.apply(sub_range1, sub_range2, policy_type()); for (std::size_t i = 0; i < is.count; i++) { PointOut p; geometry::convert(is.intersections[i], p); *out++ = p; } return out; } }; template <typename PointOut> struct intersection_linestring_linestring_point { template < typename Linestring1, typename Linestring2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linestring1 const& linestring1, Linestring2 const& linestring2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef detail::overlay::turn_info<PointOut> turn_info; std::deque<turn_info> turns; geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns, strategy); for (typename boost::range_iterator<std::deque<turn_info> const>::type it = boost::begin(turns); it != boost::end(turns); ++it) { PointOut p; geometry::convert(it->point, p); *out++ = p; } return out; } }; /*! \brief Version of linestring with an areal feature (polygon or multipolygon) */ template < bool ReverseAreal, typename GeometryOut, overlay_type OverlayType, bool FollowIsolatedPoints > struct intersection_of_linestring_with_areal { #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) template <typename Turn, typename Operation> static inline void debug_follow(Turn const& turn, Operation op, int index) { std::cout << index << " at " << op.seg_id << " meth: " << method_char(turn.method) << " op: " << operation_char(op.operation) << " vis: " << visited_char(op.visited) << " of: " << operation_char(turn.operations[0].operation) << operation_char(turn.operations[1].operation) << " " << geometry::wkt(turn.point) << std::endl; } template <typename Turn> static inline void debug_turn(Turn const& t, bool non_crossing) { std::cout << "checking turn @" << geometry::wkt(t.point) << "; " << method_char(t.method) << ":" << operation_char(t.operations[0].operation) << "/" << operation_char(t.operations[1].operation) << "; non-crossing? " << std::boolalpha << non_crossing << std::noboolalpha << std::endl; } #endif template <typename Linestring, typename Areal, typename Strategy, typename Turns> static inline bool simple_turns_analysis(Linestring const& linestring, Areal const& areal, Strategy const& strategy, Turns const& turns, int & inside_value) { using namespace overlay; bool found_continue = false; bool found_intersection = false; bool found_union = false; bool found_front = false; for (typename Turns::const_iterator it = turns.begin(); it != turns.end(); ++it) { method_type const method = it->method; operation_type const op = it->operations[0].operation; if (method == method_crosses) { return false; } else if (op == operation_intersection) { found_intersection = true; } else if (op == operation_union) { found_union = true; } else if (op == operation_continue) { found_continue = true; } if ((found_intersection || found_continue) && found_union) { return false; } if (it->operations[0].position == position_front) { found_front = true; } } if (found_front) { if (found_intersection) { inside_value = 1; // inside } else if (found_union) { inside_value = -1; // outside } else // continue and blocked { inside_value = 0; } return true; } // if needed analyse points of a linestring // NOTE: range_in_geometry checks points of a linestring // until a point inside/outside areal is found // TODO: Could be replaced with point_in_geometry() because found_front is false inside_value = range_in_geometry(linestring, areal, strategy); if ( (found_intersection && inside_value == -1) // going in from outside || (found_continue && inside_value == -1) // going on boundary from outside || (found_union && inside_value == 1) ) // going out from inside { return false; } return true; } template < typename LineString, typename Areal, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(LineString const& linestring, Areal const& areal, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); if (boost::size(linestring) == 0) { return out; } typedef detail::overlay::follow < GeometryOut, LineString, Areal, OverlayType, false, // do not remove spikes for linear geometries FollowIsolatedPoints > follower; typedef typename geometry::detail::output_geometry_access < GeometryOut, linestring_tag, linestring_tag > linear; typedef typename point_type < typename linear::type >::type point_type; typedef geometry::segment_ratio < typename coordinate_type<point_type>::type > ratio_type; typedef detail::overlay::turn_info < point_type, ratio_type, detail::overlay::turn_operation_linear < point_type, ratio_type > > turn_info; std::deque<turn_info> turns; detail::get_turns::no_interrupt_policy policy; typedef detail::overlay::get_turn_info_linear_areal < detail::overlay::assign_null_policy > turn_policy; dispatch::get_turns < typename geometry::tag<LineString>::type, typename geometry::tag<Areal>::type, LineString, Areal, false, (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), turn_policy >::apply(0, linestring, 1, areal, strategy, robust_policy, turns, policy); int inside_value = 0; if (simple_turns_analysis(linestring, areal, strategy, turns, inside_value)) { // No crossing the boundary, it is either // inside (interior + borders) // or outside (exterior + borders) // or on boundary // add linestring to the output if conditions are met if (follower::included(inside_value)) { typename linear::type copy; geometry::convert(linestring, copy); *linear::get(out)++ = copy; } return out; } #if defined(BOOST_GEOMETRY_DEBUG_FOLLOW) int index = 0; for(typename std::deque<turn_info>::const_iterator it = turns.begin(); it != turns.end(); ++it) { debug_follow(*it, it->operations[0], index++); } #endif return follower::apply ( linestring, areal, geometry::detail::overlay::operation_intersection, turns, robust_policy, out, strategy ); } }; template <typename Turns, typename OutputIterator> inline OutputIterator intersection_output_turn_points(Turns const& turns, OutputIterator out) { for (typename Turns::const_iterator it = turns.begin(); it != turns.end(); ++it) { *out++ = it->point; } return out; } template <typename PointOut> struct intersection_areal_areal_point { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { typedef detail::overlay::turn_info < PointOut, typename segment_ratio_type<PointOut, RobustPolicy>::type > turn_info; std::vector<turn_info> turns; detail::get_turns::no_interrupt_policy policy; geometry::get_turns < false, false, detail::overlay::assign_null_policy >(geometry1, geometry2, strategy, robust_policy, turns, policy); return intersection_output_turn_points(turns, out); } }; template <typename PointOut> struct intersection_linear_areal_point { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef geometry::segment_ratio<typename geometry::coordinate_type<PointOut>::type> ratio_type; typedef detail::overlay::turn_info < PointOut, ratio_type, detail::overlay::turn_operation_linear < PointOut, ratio_type > > turn_info; typedef detail::overlay::get_turn_info_linear_areal < detail::overlay::assign_null_policy > turn_policy; std::vector<turn_info> turns; detail::get_turns::no_interrupt_policy interrupt_policy; dispatch::get_turns < typename geometry::tag<Geometry1>::type, typename geometry::tag<Geometry2>::type, Geometry1, Geometry2, false, false, turn_policy >::apply(0, geometry1, 1, geometry2, strategy, robust_policy, turns, interrupt_policy); return intersection_output_turn_points(turns, out); } }; template <typename PointOut> struct intersection_areal_linear_point { template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return intersection_linear_areal_point < PointOut >::apply(geometry2, geometry1, robust_policy, out, strategy); } }; }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < // real types typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, // orientation bool Reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, bool Reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, // tag dispatching: typename TagIn1 = typename geometry::tag<Geometry1>::type, typename TagIn2 = typename geometry::tag<Geometry2>::type, typename TagOut = typename detail::setop_insert_output_tag<GeometryOut>::type, // metafunction finetuning helpers: typename CastedTagIn1 = typename geometry::tag_cast<TagIn1, areal_tag, linear_tag, pointlike_tag>::type, typename CastedTagIn2 = typename geometry::tag_cast<TagIn2, areal_tag, linear_tag, pointlike_tag>::type, typename CastedTagOut = typename geometry::tag_cast<TagOut, areal_tag, linear_tag, pointlike_tag>::type > struct intersection_insert { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for these Geometry types or their order.", Geometry1, Geometry2, GeometryOut, std::integral_constant<overlay_type, OverlayType>); }; template < typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2, typename TagOut > struct intersection_insert < Geometry1, Geometry2, GeometryOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, TagOut, areal_tag, areal_tag, areal_tag > : detail::overlay::overlay < Geometry1, Geometry2, Reverse1, Reverse2, detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, GeometryOut, OverlayType > {}; // Any areal type with box: template < typename Geometry, typename Box, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn, typename TagOut > struct intersection_insert < Geometry, Box, GeometryOut, OverlayType, Reverse1, Reverse2, TagIn, box_tag, TagOut, areal_tag, areal_tag, areal_tag > : detail::overlay::overlay < Geometry, Box, Reverse1, Reverse2, detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, GeometryOut, OverlayType > {}; template < typename Segment1, typename Segment2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Segment1, Segment2, GeometryOut, OverlayType, Reverse1, Reverse2, segment_tag, segment_tag, point_tag, linear_tag, linear_tag, pointlike_tag > : detail::intersection::intersection_segment_segment_point<GeometryOut> {}; template < typename Linestring1, typename Linestring2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring1, Linestring2, GeometryOut, OverlayType, Reverse1, Reverse2, linestring_tag, linestring_tag, point_tag, linear_tag, linear_tag, pointlike_tag > : detail::intersection::intersection_linestring_linestring_point<GeometryOut> {}; template < typename Linestring, typename Box, typename GeometryOut, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, Box, GeometryOut, overlay_intersection, Reverse1, Reverse2, linestring_tag, box_tag, linestring_tag, linear_tag, areal_tag, linear_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Linestring const& linestring, Box const& box, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { typedef typename point_type<GeometryOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; return detail::intersection::clip_range_with_box <GeometryOut>(box, linestring, robust_policy, out, lb_strategy); } }; template < typename Linestring, typename Polygon, typename GeometryOut, overlay_type OverlayType, bool ReverseLinestring, bool ReversePolygon > struct intersection_insert < Linestring, Polygon, GeometryOut, OverlayType, ReverseLinestring, ReversePolygon, linestring_tag, polygon_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_linestring_with_areal < ReversePolygon, GeometryOut, OverlayType, false > {}; template < typename Linestring, typename Ring, typename GeometryOut, overlay_type OverlayType, bool ReverseLinestring, bool ReverseRing > struct intersection_insert < Linestring, Ring, GeometryOut, OverlayType, ReverseLinestring, ReverseRing, linestring_tag, ring_tag, linestring_tag, linear_tag, areal_tag, linear_tag > : detail::intersection::intersection_of_linestring_with_areal < ReverseRing, GeometryOut, OverlayType, false > {}; template < typename Segment, typename Box, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Segment, Box, GeometryOut, OverlayType, Reverse1, Reverse2, segment_tag, box_tag, linestring_tag, linear_tag, areal_tag, linear_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Segment const& segment, Box const& box, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { geometry::segment_view<Segment> range(segment); typedef typename point_type<GeometryOut>::type point_type; strategy::intersection::liang_barsky<Box, point_type> lb_strategy; return detail::intersection::clip_range_with_box <GeometryOut>(box, range, robust_policy, out, lb_strategy); } }; template < typename Geometry1, typename Geometry2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, PointOut, OverlayType, Reverse1, Reverse2, Tag1, Tag2, point_tag, areal_tag, areal_tag, pointlike_tag > : public detail::intersection::intersection_areal_areal_point < PointOut > {}; template < typename Geometry1, typename Geometry2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, PointOut, OverlayType, Reverse1, Reverse2, Tag1, Tag2, point_tag, linear_tag, areal_tag, pointlike_tag > : public detail::intersection::intersection_linear_areal_point < PointOut > {}; template < typename Geometry1, typename Geometry2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, PointOut, OverlayType, Reverse1, Reverse2, Tag1, Tag2, point_tag, areal_tag, linear_tag, pointlike_tag > : public detail::intersection::intersection_areal_linear_point < PointOut > {}; template < typename Geometry1, typename Geometry2, typename GeometryOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert_reversed { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return intersection_insert < Geometry2, Geometry1, GeometryOut, OverlayType, Reverse2, Reverse1 >::apply(g2, g1, robust_policy, out, strategy); } }; // dispatch for intersection(areal, areal, linear) template < typename Geometry1, typename Geometry2, typename LinestringOut, bool Reverse1, bool Reverse2, typename Tag1, typename Tag2 > struct intersection_insert < Geometry1, Geometry2, LinestringOut, overlay_intersection, Reverse1, Reverse2, Tag1, Tag2, linestring_tag, areal_tag, areal_tag, linear_tag > { template < typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { detail::boundary_view<Geometry1 const> view1(geometry1); detail::boundary_view<Geometry2 const> view2(geometry2); return detail::overlay::linear_linear_linestring < detail::boundary_view<Geometry1 const>, detail::boundary_view<Geometry2 const>, LinestringOut, overlay_intersection >::apply(view1, view2, robust_policy, oit, strategy); } }; // dispatch for difference/intersection of linear geometries template < typename Linear1, typename Linear2, typename LineStringOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < Linear1, Linear2, LineStringOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, linestring_tag, linear_tag, linear_tag, linear_tag > : detail::overlay::linear_linear_linestring < Linear1, Linear2, LineStringOut, OverlayType > {}; template < typename Linear1, typename Linear2, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < Linear1, Linear2, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, linear_tag, linear_tag, detail::tupled_output_tag > : detail::expect_output < Linear1, Linear2, TupledOut, // NOTE: points can be the result only in case of intersection. std::conditional_t < (OverlayType == overlay_intersection), point_tag, void >, linestring_tag > { // NOTE: The order of geometries in TupledOut tuple/pair must correspond to the order // iterators in OutputIterators tuple/pair. template < typename RobustPolicy, typename OutputIterators, typename Strategy > static inline OutputIterators apply(Linear1 const& linear1, Linear2 const& linear2, RobustPolicy const& robust_policy, OutputIterators oit, Strategy const& strategy) { return detail::overlay::linear_linear_linestring < Linear1, Linear2, TupledOut, OverlayType >::apply(linear1, linear2, robust_policy, oit, strategy); } }; // dispatch for difference/intersection of point-like geometries template < typename Point1, typename Point2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Point1, Point2, PointOut, OverlayType, Reverse1, Reverse2, point_tag, point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::point_point_point < Point1, Point2, PointOut, OverlayType > {}; template < typename MultiPoint, typename Point, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < MultiPoint, Point, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::multipoint_point_point < MultiPoint, Point, PointOut, OverlayType > {}; template < typename Point, typename MultiPoint, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < Point, MultiPoint, PointOut, OverlayType, Reverse1, Reverse2, point_tag, multi_point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::point_multipoint_point < Point, MultiPoint, PointOut, OverlayType > {}; template < typename MultiPoint1, typename MultiPoint2, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2 > struct intersection_insert < MultiPoint1, MultiPoint2, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, multi_point_tag, point_tag, pointlike_tag, pointlike_tag, pointlike_tag > : detail::overlay::multipoint_multipoint_point < MultiPoint1, MultiPoint2, PointOut, OverlayType > {}; template < typename PointLike1, typename PointLike2, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < PointLike1, PointLike2, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, pointlike_tag, detail::tupled_output_tag > : detail::expect_output<PointLike1, PointLike2, TupledOut, point_tag> { // NOTE: The order of geometries in TupledOut tuple/pair must correspond to the order // of iterators in OutputIterators tuple/pair. template < typename RobustPolicy, typename OutputIterators, typename Strategy > static inline OutputIterators apply(PointLike1 const& pointlike1, PointLike2 const& pointlike2, RobustPolicy const& robust_policy, OutputIterators oits, Strategy const& strategy) { namespace bgt = boost::geometry::tuples; static const bool out_point_index = bgt::find_index_if < TupledOut, geometry::detail::is_tag_same_as_pred<point_tag>::template pred >::value; bgt::get<out_point_index>(oits) = intersection_insert < PointLike1, PointLike2, typename bgt::element < out_point_index, TupledOut >::type, OverlayType >::apply(pointlike1, pointlike2, robust_policy, bgt::get<out_point_index>(oits), strategy); return oits; } }; // dispatch for difference/intersection of pointlike-linear geometries template < typename Point, typename Linear, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag > struct intersection_insert < Point, Linear, PointOut, OverlayType, Reverse1, Reverse2, point_tag, Tag, point_tag, pointlike_tag, linear_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_linear_point < Point, Linear, PointOut, OverlayType, point_tag, typename tag_cast<Tag, segment_tag, linear_tag>::type > {}; template < typename MultiPoint, typename Linear, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename Tag > struct intersection_insert < MultiPoint, Linear, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, Tag, point_tag, pointlike_tag, linear_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_linear_point < MultiPoint, Linear, PointOut, OverlayType, multi_point_tag, typename tag_cast<Tag, segment_tag, linear_tag>::type > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Linestring combination. template < typename Linestring, typename MultiPoint, typename PointOut, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, MultiPoint, PointOut, overlay_intersection, Reverse1, Reverse2, linestring_tag, multi_point_tag, point_tag, linear_tag, pointlike_tag, pointlike_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Linestring const& linestring, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return detail_dispatch::overlay::pointlike_linear_point < MultiPoint, Linestring, PointOut, overlay_intersection, multi_point_tag, linear_tag >::apply(multipoint, linestring, robust_policy, out, strategy); } }; template < typename PointLike, typename Linear, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < PointLike, Linear, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, linear_tag, detail::tupled_output_tag > // Reuse the implementation for PointLike/PointLike. : intersection_insert < PointLike, Linear, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, pointlike_tag, detail::tupled_output_tag > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Linestring combination. template < typename Linestring, typename MultiPoint, typename TupledOut, bool Reverse1, bool Reverse2 > struct intersection_insert < Linestring, MultiPoint, TupledOut, overlay_intersection, Reverse1, Reverse2, linestring_tag, multi_point_tag, detail::tupled_output_tag, linear_tag, pointlike_tag, detail::tupled_output_tag > { template <typename RobustPolicy, typename OutputIterators, typename Strategy> static inline OutputIterators apply(Linestring const& linestring, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterators out, Strategy const& strategy) { return intersection_insert < MultiPoint, Linestring, TupledOut, overlay_intersection >::apply(multipoint, linestring, robust_policy, out, strategy); } }; // dispatch for difference/intersection of pointlike-areal geometries template < typename Point, typename Areal, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename ArealTag > struct intersection_insert < Point, Areal, PointOut, OverlayType, Reverse1, Reverse2, point_tag, ArealTag, point_tag, pointlike_tag, areal_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_areal_point < Point, Areal, PointOut, OverlayType, point_tag, ArealTag > {}; template < typename MultiPoint, typename Areal, typename PointOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename ArealTag > struct intersection_insert < MultiPoint, Areal, PointOut, OverlayType, Reverse1, Reverse2, multi_point_tag, ArealTag, point_tag, pointlike_tag, areal_tag, pointlike_tag > : detail_dispatch::overlay::pointlike_areal_point < MultiPoint, Areal, PointOut, OverlayType, multi_point_tag, ArealTag > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Ring and MultiPoint/Polygon combinations. template < typename Areal, typename MultiPoint, typename PointOut, bool Reverse1, bool Reverse2, typename ArealTag > struct intersection_insert < Areal, MultiPoint, PointOut, overlay_intersection, Reverse1, Reverse2, ArealTag, multi_point_tag, point_tag, areal_tag, pointlike_tag, pointlike_tag > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Areal const& areal, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return detail_dispatch::overlay::pointlike_areal_point < MultiPoint, Areal, PointOut, overlay_intersection, multi_point_tag, ArealTag >::apply(multipoint, areal, robust_policy, out, strategy); } }; template < typename PointLike, typename Areal, typename TupledOut, overlay_type OverlayType, bool Reverse1, bool Reverse2, typename TagIn1, typename TagIn2 > struct intersection_insert < PointLike, Areal, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, areal_tag, detail::tupled_output_tag > // Reuse the implementation for PointLike/PointLike. : intersection_insert < PointLike, Areal, TupledOut, OverlayType, Reverse1, Reverse2, TagIn1, TagIn2, detail::tupled_output_tag, pointlike_tag, pointlike_tag, detail::tupled_output_tag > {}; // This specialization is needed because intersection() reverses the arguments // for MultiPoint/Ring and MultiPoint/Polygon combinations. template < typename Areal, typename MultiPoint, typename TupledOut, bool Reverse1, bool Reverse2, typename TagIn1 > struct intersection_insert < Areal, MultiPoint, TupledOut, overlay_intersection, Reverse1, Reverse2, TagIn1, multi_point_tag, detail::tupled_output_tag, areal_tag, pointlike_tag, detail::tupled_output_tag > { template <typename RobustPolicy, typename OutputIterators, typename Strategy> static inline OutputIterators apply(Areal const& areal, MultiPoint const& multipoint, RobustPolicy const& robust_policy, OutputIterators out, Strategy const& strategy) { return intersection_insert < MultiPoint, Areal, TupledOut, overlay_intersection >::apply(multipoint, areal, robust_policy, out, strategy); } }; template < typename Linestring, typename Polygon, typename TupledOut, overlay_type OverlayType, bool ReverseLinestring, bool ReversePolygon > struct intersection_insert < Linestring, Polygon, TupledOut, OverlayType, ReverseLinestring, ReversePolygon, linestring_tag, polygon_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_linestring_with_areal < ReversePolygon, TupledOut, OverlayType, true > {}; template < typename Linestring, typename Ring, typename TupledOut, overlay_type OverlayType, bool ReverseLinestring, bool ReverseRing > struct intersection_insert < Linestring, Ring, TupledOut, OverlayType, ReverseLinestring, ReverseRing, linestring_tag, ring_tag, detail::tupled_output_tag, linear_tag, areal_tag, detail::tupled_output_tag > : detail::intersection::intersection_of_linestring_with_areal < ReverseRing, TupledOut, OverlayType, true > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template < typename GeometryOut, bool ReverseSecond, overlay_type OverlayType, typename Geometry1, typename Geometry2, typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator insert(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy robust_policy, OutputIterator out, Strategy const& strategy) { return std::conditional_t < geometry::reverse_dispatch<Geometry1, Geometry2>::type::value, geometry::dispatch::intersection_insert_reversed < Geometry1, Geometry2, GeometryOut, OverlayType, overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value >, geometry::dispatch::intersection_insert < Geometry1, Geometry2, GeometryOut, OverlayType, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value > >::apply(geometry1, geometry2, robust_policy, out, strategy); } /*! \brief \brief_calc2{intersection} \brief_strategy \ingroup intersection \details \details_calc2{intersection_insert, spatial set theoretic intersection} \brief_strategy. \details_insert{intersection} \tparam GeometryOut \tparam_geometry{\p_l_or_c} \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator \tparam_out{\p_l_or_c} \tparam Strategy \tparam_strategy_overlay \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{intersection} \param strategy \param_strategy{intersection} \return \return_out \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator, typename Strategy > inline OutputIterator intersection_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return detail::intersection::insert < GeometryOut, false, overlay_intersection >(geometry1, geometry2, robust_policy, out, strategy); } /*! \brief \brief_calc2{intersection} \ingroup intersection \details \details_calc2{intersection_insert, spatial set theoretic intersection}. \details_insert{intersection} \tparam GeometryOut \tparam_geometry{\p_l_or_c} \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator \tparam_out{\p_l_or_c} \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{intersection} \return \return_out \qbk{[include reference/algorithms/intersection.qbk]} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator > inline OutputIterator intersection_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); typedef typename strategy::intersection::services::default_strategy < typename cs_tag<GeometryOut>::type >::type strategy_type; return intersection_insert<GeometryOut>(geometry1, geometry2, out, strategy_type()); } }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP detail/overlay/pointlike_pointlike.hpp 0000644 00000027321 15125631657 0014274 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP #include <algorithm> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/policies/compare.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // struct for copying points of the pointlike geometries to output template < typename PointOut, typename GeometryIn, typename TagIn = typename tag<GeometryIn>::type > struct copy_points : not_implemented<PointOut, GeometryIn> {}; template <typename PointOut, typename PointIn> struct copy_points<PointOut, PointIn, point_tag> { template <typename OutputIterator> static inline void apply(PointIn const& point_in, OutputIterator& oit) { PointOut point_out; geometry::convert(point_in, point_out); *oit++ = point_out; } }; template <typename PointOut, typename MultiPointIn> struct copy_points<PointOut, MultiPointIn, multi_point_tag> { template <typename OutputIterator> static inline void apply(MultiPointIn const& multi_point_in, OutputIterator& oit) { for (typename boost::range_iterator<MultiPointIn const>::type it = boost::begin(multi_point_in); it != boost::end(multi_point_in); ++it) { PointOut point_out; geometry::convert(*it, point_out); *oit++ = point_out; } } }; // action struct for difference/intersection template <typename PointOut, overlay_type OverlayType> struct action_selector_pl {}; template <typename PointOut> struct action_selector_pl<PointOut, overlay_intersection> { template < typename Point, typename OutputIterator > static inline void apply(Point const& point, bool is_common, OutputIterator& oit) { if ( is_common ) { copy_points<PointOut, Point>::apply(point, oit); } } }; template <typename PointOut> struct action_selector_pl<PointOut, overlay_difference> { template < typename Point, typename OutputIterator > static inline void apply(Point const& point, bool is_common, OutputIterator& oit) { if ( !is_common ) { copy_points<PointOut, Point>::apply(point, oit); } } }; //=========================================================================== // difference/intersection of point-point template < typename Point1, typename Point2, typename PointOut, overlay_type OverlayType > struct point_point_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Point1 const& point1, Point2 const& point2, RobustPolicy const& , OutputIterator oit, Strategy const& strategy) { action_selector_pl < PointOut, OverlayType >::apply(point1, detail::equals::equals_point_point(point1, point2, strategy), oit); return oit; } }; // difference of multipoint-point // // the apply method in the following struct is called only for // difference; for intersection the reversal will // always call the point-multipoint version template < typename MultiPoint, typename Point, typename PointOut, overlay_type OverlayType > struct multipoint_point_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(MultiPoint const& multipoint, Point const& point, RobustPolicy const& , OutputIterator oit, Strategy const& strategy) { BOOST_GEOMETRY_ASSERT( OverlayType == overlay_difference ); for (typename boost::range_iterator<MultiPoint const>::type it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { action_selector_pl < PointOut, OverlayType >::apply(*it, detail::equals::equals_point_point(*it, point, strategy), oit); } return oit; } }; // difference/intersection of point-multipoint template < typename Point, typename MultiPoint, typename PointOut, overlay_type OverlayType > struct point_multipoint_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Point const& point, MultiPoint const& multipoint, RobustPolicy const& , OutputIterator oit, Strategy const& strategy) { typedef action_selector_pl<PointOut, OverlayType> action; for (typename boost::range_iterator<MultiPoint const>::type it = boost::begin(multipoint); it != boost::end(multipoint); ++it) { if ( detail::equals::equals_point_point(*it, point, strategy) ) { action::apply(point, true, oit); return oit; } } action::apply(point, false, oit); return oit; } }; // difference/intersection of multipoint-multipoint template < typename MultiPoint1, typename MultiPoint2, typename PointOut, overlay_type OverlayType > struct multipoint_multipoint_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(MultiPoint1 const& multipoint1, MultiPoint2 const& multipoint2, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { typedef geometry::less<void, -1, typename Strategy::cs_tag> less_type; if ( OverlayType != overlay_difference && boost::size(multipoint1) > boost::size(multipoint2) ) { return multipoint_multipoint_point < MultiPoint2, MultiPoint1, PointOut, OverlayType >::apply(multipoint2, multipoint1, robust_policy, oit, strategy); } typedef typename boost::range_value<MultiPoint2>::type point2_type; std::vector<point2_type> points2(boost::begin(multipoint2), boost::end(multipoint2)); less_type const less = less_type(); std::sort(points2.begin(), points2.end(), less); for (typename boost::range_iterator<MultiPoint1 const>::type it1 = boost::begin(multipoint1); it1 != boost::end(multipoint1); ++it1) { bool found = std::binary_search(points2.begin(), points2.end(), *it1, less); action_selector_pl < PointOut, OverlayType >::apply(*it1, found, oit); } return oit; } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL //=========================================================================== #ifndef DOXYGEN_NO_DISPATCH namespace detail_dispatch { namespace overlay { // dispatch struct for pointlike-pointlike difference/intersection // computation template < typename PointLike1, typename PointLike2, typename PointOut, overlay_type OverlayType, typename Tag1, typename Tag2 > struct pointlike_pointlike_point : not_implemented<PointLike1, PointLike2, PointOut> {}; template < typename Point1, typename Point2, typename PointOut, overlay_type OverlayType > struct pointlike_pointlike_point < Point1, Point2, PointOut, OverlayType, point_tag, point_tag > : detail::overlay::point_point_point < Point1, Point2, PointOut, OverlayType > {}; template < typename Point, typename MultiPoint, typename PointOut, overlay_type OverlayType > struct pointlike_pointlike_point < Point, MultiPoint, PointOut, OverlayType, point_tag, multi_point_tag > : detail::overlay::point_multipoint_point < Point, MultiPoint, PointOut, OverlayType > {}; template < typename MultiPoint, typename Point, typename PointOut, overlay_type OverlayType > struct pointlike_pointlike_point < MultiPoint, Point, PointOut, OverlayType, multi_point_tag, point_tag > : detail::overlay::multipoint_point_point < MultiPoint, Point, PointOut, OverlayType > {}; template < typename MultiPoint1, typename MultiPoint2, typename PointOut, overlay_type OverlayType > struct pointlike_pointlike_point < MultiPoint1, MultiPoint2, PointOut, OverlayType, multi_point_tag, multi_point_tag > : detail::overlay::multipoint_multipoint_point < MultiPoint1, MultiPoint2, PointOut, OverlayType > {}; }} // namespace detail_dispatch::overlay #endif // DOXYGEN_NO_DISPATCH //=========================================================================== #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // generic pointlike-pointlike union implementation template < typename PointLike1, typename PointLike2, typename PointOut > struct union_pointlike_pointlike_point { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(PointLike1 const& pointlike1, PointLike2 const& pointlike2, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { copy_points<PointOut, PointLike1>::apply(pointlike1, oit); return detail_dispatch::overlay::pointlike_pointlike_point < PointLike2, PointLike1, PointOut, overlay_difference, typename tag<PointLike2>::type, typename tag<PointLike1>::type >::apply(pointlike2, pointlike1, robust_policy, oit, strategy); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_POINTLIKE_POINTLIKE_HPP detail/overlay/follow_linear_linear.hpp 0000644 00000036712 15125631657 0014412 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP #include <cstddef> #include <algorithm> #include <iterator> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/throw_exception.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/follow.hpp> #include <boost/geometry/algorithms/detail/overlay/inconsistent_turns_exception.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/turns/debug_turn.hpp> #include <boost/geometry/algorithms/detail/tupled_output.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { namespace following { namespace linear { // follower for linear/linear geometries set operations template <typename Turn, typename Operation> static inline bool is_entering(Turn const& turn, Operation const& operation) { if ( turn.method != method_touch && turn.method != method_touch_interior ) { return false; } return operation.operation == operation_intersection; } template <typename Turn, typename Operation> static inline bool is_staying_inside(Turn const& turn, Operation const& operation, bool entered) { if ( !entered ) { return false; } if ( turn.method != method_equal && turn.method != method_collinear ) { return false; } return operation.operation == operation_continue; } template <typename Turn, typename Operation> static inline bool is_leaving(Turn const& turn, Operation const& operation, bool entered) { if ( !entered ) { return false; } if ( turn.method != method_touch && turn.method != method_touch_interior && turn.method != method_equal && turn.method != method_collinear ) { return false; } if ( operation.operation == operation_blocked ) { return true; } if ( operation.operation != operation_union ) { return false; } return operation.is_collinear; } template <typename Turn, typename Operation> static inline bool is_isolated_point(Turn const& turn, Operation const& operation, bool entered) { if ( entered ) { return false; } if ( turn.method == method_none ) { BOOST_GEOMETRY_ASSERT( operation.operation == operation_continue ); return true; } if ( turn.method == method_crosses ) { return true; } if ( turn.method != method_touch && turn.method != method_touch_interior ) { return false; } if ( operation.operation == operation_blocked ) { return true; } if ( operation.operation != operation_union ) { return false; } return !operation.is_collinear; } // GeometryOut - linestring or tuple of at least point and linestring template < typename GeometryOut, typename Linestring, typename Linear, overlay_type OverlayType, bool FollowIsolatedPoints, bool FollowContinueTurns > class follow_linestring_linear { protected: // allow spikes (false indicates: do not remove spikes) typedef following::action_selector<OverlayType, false> action; typedef geometry::detail::output_geometry_access < GeometryOut, linestring_tag, linestring_tag > linear; typedef geometry::detail::output_geometry_access < GeometryOut, point_tag, linestring_tag > pointlike; template < typename TurnIterator, typename TurnOperationIterator, typename LinestringOut, typename SegmentIdentifier, typename OutputIterator, typename SideStrategy > static inline OutputIterator process_turn(TurnIterator it, TurnOperationIterator op_it, bool& entered, std::size_t& enter_count, Linestring const& linestring, LinestringOut& current_piece, SegmentIdentifier& current_segment_id, OutputIterator oit, SideStrategy const& strategy) { // We don't rescale linear/linear detail::no_rescale_policy robust_policy; if ( is_entering(*it, *op_it) ) { detail::turns::debug_turn(*it, *op_it, "-> Entering"); entered = true; if ( enter_count == 0 ) { action::enter(current_piece, linestring, current_segment_id, op_it->seg_id.segment_index, it->point, *op_it, strategy, robust_policy, linear::get(oit)); } ++enter_count; } else if ( is_leaving(*it, *op_it, entered) ) { detail::turns::debug_turn(*it, *op_it, "-> Leaving"); --enter_count; if ( enter_count == 0 ) { entered = false; action::leave(current_piece, linestring, current_segment_id, op_it->seg_id.segment_index, it->point, *op_it, strategy, robust_policy, linear::get(oit)); } } else if ( BOOST_GEOMETRY_CONDITION(FollowIsolatedPoints) && is_isolated_point(*it, *op_it, entered) ) { detail::turns::debug_turn(*it, *op_it, "-> Isolated point"); action::template isolated_point < typename pointlike::type >(it->point, pointlike::get(oit)); } else if ( BOOST_GEOMETRY_CONDITION(FollowContinueTurns) && is_staying_inside(*it, *op_it, entered) ) { detail::turns::debug_turn(*it, *op_it, "-> Staying inside"); entered = true; } return oit; } template < typename SegmentIdentifier, typename LinestringOut, typename OutputIterator, typename SideStrategy > static inline OutputIterator process_end(bool entered, Linestring const& linestring, SegmentIdentifier const& current_segment_id, LinestringOut& current_piece, OutputIterator oit, SideStrategy const& strategy) { if ( action::is_entered(entered) ) { // We don't rescale linear/linear detail::no_rescale_policy robust_policy; detail::copy_segments::copy_segments_linestring < false, false // do not reverse; do not remove spikes >::apply(linestring, current_segment_id, static_cast<signed_size_type>(boost::size(linestring) - 1), strategy, robust_policy, current_piece); } // Output the last one, if applicable if (::boost::size(current_piece) > 1) { *linear::get(oit)++ = current_piece; } return oit; } public: template <typename TurnIterator, typename OutputIterator, typename SideStrategy> static inline OutputIterator apply(Linestring const& linestring, Linear const&, TurnIterator first, TurnIterator beyond, OutputIterator oit, SideStrategy const& strategy) { // Iterate through all intersection points (they are // ordered along the each line) typename linear::type current_piece; geometry::segment_identifier current_segment_id(0, -1, -1, -1); bool entered = false; std::size_t enter_count = 0; for (TurnIterator it = first; it != beyond; ++it) { oit = process_turn(it, boost::begin(it->operations), entered, enter_count, linestring, current_piece, current_segment_id, oit, strategy); } #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) if (enter_count != 0) { BOOST_THROW_EXCEPTION(inconsistent_turns_exception()); } #else BOOST_GEOMETRY_ASSERT(enter_count == 0); #endif return process_end(entered, linestring, current_segment_id, current_piece, oit, strategy); } }; template < typename LinestringOut, typename MultiLinestring, typename Linear, overlay_type OverlayType, bool FollowIsolatedPoints, bool FollowContinueTurns > class follow_multilinestring_linear : follow_linestring_linear < LinestringOut, typename boost::range_value<MultiLinestring>::type, Linear, OverlayType, FollowIsolatedPoints, FollowContinueTurns > { protected: typedef typename boost::range_value<MultiLinestring>::type Linestring; typedef follow_linestring_linear < LinestringOut, Linestring, Linear, OverlayType, FollowIsolatedPoints, FollowContinueTurns > Base; typedef following::action_selector<OverlayType> action; typedef typename boost::range_iterator < MultiLinestring const >::type linestring_iterator; template <typename OutputIt, overlay_type OT> struct copy_linestrings_in_range { static inline OutputIt apply(linestring_iterator, linestring_iterator, OutputIt oit) { return oit; } }; template <typename OutputIt> struct copy_linestrings_in_range<OutputIt, overlay_difference> { static inline OutputIt apply(linestring_iterator first, linestring_iterator beyond, OutputIt oit) { for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it) { LinestringOut line_out; geometry::convert(*ls_it, line_out); *oit++ = line_out; } return oit; } }; template <typename TurnIterator> static inline signed_size_type get_multi_index(TurnIterator it) { return boost::begin(it->operations)->seg_id.multi_index; } class has_other_multi_id { private: signed_size_type m_multi_id; public: has_other_multi_id(signed_size_type multi_id) : m_multi_id(multi_id) {} template <typename Turn> bool operator()(Turn const& turn) const { return boost::begin(turn.operations)->seg_id.multi_index != m_multi_id; } }; public: template <typename TurnIterator, typename OutputIterator, typename SideStrategy> static inline OutputIterator apply(MultiLinestring const& multilinestring, Linear const& linear, TurnIterator first, TurnIterator beyond, OutputIterator oit, SideStrategy const& strategy) { BOOST_GEOMETRY_ASSERT( first != beyond ); typedef copy_linestrings_in_range < OutputIterator, OverlayType > copy_linestrings; linestring_iterator ls_first = boost::begin(multilinestring); linestring_iterator ls_beyond = boost::end(multilinestring); // Iterate through all intersection points (they are // ordered along the each linestring) signed_size_type current_multi_id = get_multi_index(first); oit = copy_linestrings::apply(ls_first, ls_first + current_multi_id, oit); TurnIterator per_ls_next = first; do { TurnIterator per_ls_current = per_ls_next; // find turn with different multi-index per_ls_next = std::find_if(per_ls_current, beyond, has_other_multi_id(current_multi_id)); oit = Base::apply(*(ls_first + current_multi_id), linear, per_ls_current, per_ls_next, oit, strategy); signed_size_type next_multi_id = -1; linestring_iterator ls_next = ls_beyond; if ( per_ls_next != beyond ) { next_multi_id = get_multi_index(per_ls_next); ls_next = ls_first + next_multi_id; } oit = copy_linestrings::apply(ls_first + current_multi_id + 1, ls_next, oit); current_multi_id = next_multi_id; } while ( per_ls_next != beyond ); return oit; } }; template < typename LinestringOut, typename Geometry1, typename Geometry2, overlay_type OverlayType, bool FollowIsolatedPoints, bool FollowContinueTurns, typename TagIn1 = typename tag<Geometry1>::type > struct follow : not_implemented<Geometry1> {}; template < typename LinestringOut, typename Linestring, typename Linear, overlay_type OverlayType, bool FollowIsolatedPoints, bool FollowContinueTurns > struct follow < LinestringOut, Linestring, Linear, OverlayType, FollowIsolatedPoints, FollowContinueTurns, linestring_tag > : follow_linestring_linear < LinestringOut, Linestring, Linear, OverlayType, FollowIsolatedPoints, FollowContinueTurns > {}; template < typename LinestringOut, typename MultiLinestring, typename Linear, overlay_type OverlayType, bool FollowIsolatedPoints, bool FollowContinueTurns > struct follow < LinestringOut, MultiLinestring, Linear, OverlayType, FollowIsolatedPoints, FollowContinueTurns, multi_linestring_tag > : follow_multilinestring_linear < LinestringOut, MultiLinestring, Linear, OverlayType, FollowIsolatedPoints, FollowContinueTurns > {}; }} // namespace following::linear }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP detail/overlay/get_turn_info_la.hpp 0000644 00000104175 15125631657 0013541 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP #include <boost/throw_exception.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/util/condition.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> // TEMP, for spikes detector //#include <boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template<typename AssignPolicy> struct get_turn_info_linear_areal { // Currently only Linear spikes are handled // Areal spikes are ignored static const bool handle_spikes = true; template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnInfo, typename UmbrellaStrategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo const& tp_model, UmbrellaStrategy const& umbrella_strategy, RobustPolicy const& robust_policy, OutputIterator out) { typedef intersection_info < UniqueSubRange1, UniqueSubRange2, typename TurnInfo::point_type, UmbrellaStrategy, RobustPolicy > inters_info; inters_info inters(range_p, range_q, umbrella_strategy, robust_policy); char const method = inters.d_info().how; // Copy, to copy possibly extended fields TurnInfo tp = tp_model; // Select method and apply switch(method) { case 'a' : // collinear, "at" case 'f' : // collinear, "from" case 's' : // starts from the middle get_turn_info_for_endpoint<true, true>(range_p, range_q, tp_model, inters, method_none, out, umbrella_strategy.get_point_in_point_strategy()); break; case 'd' : // disjoint: never do anything break; case 'm' : { if ( get_turn_info_for_endpoint<false, true>(range_p, range_q, tp_model, inters, method_touch_interior, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { typedef touch_interior<TurnInfo> handler; // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1 ) { handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); } else { // Swap p/q handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), inters.get_swapped_sides(), umbrella_strategy); } if ( tp.operations[1].operation == operation_blocked ) { tp.operations[0].is_collinear = true; } replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); // this function assumes that 'u' must be set for a spike calculate_spike_operation(tp.operations[0].operation, inters, umbrella_strategy.get_point_in_point_strategy()); *out++ = tp; } } break; case 'i' : { crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info()); replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); *out++ = tp; } break; case 't' : { // Both touch (both arrive there) if ( get_turn_info_for_endpoint<false, true>(range_p, range_q, tp_model, inters, method_touch, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); if ( tp.operations[1].operation == operation_blocked ) { tp.operations[0].is_collinear = true; } // workarounds for touch<> not taking spikes into account starts here // those was discovered empirically // touch<> is not symmetrical! // P spikes and Q spikes may produce various operations! // Only P spikes are valid for L/A // TODO: this is not optimal solution - think about rewriting touch<> if ( tp.operations[0].operation == operation_blocked ) { // a spike on P on the same line with Q1 if ( inters.is_spike_p() ) { if ( inters.sides().qk_wrt_p1() == 0 ) { tp.operations[0].is_collinear = true; } else { tp.operations[0].operation = operation_union; } } } else if ( tp.operations[0].operation == operation_continue && tp.operations[1].operation == operation_continue ) { // P spike on the same line with Q2 (opposite) if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1() && inters.is_spike_p() ) { tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_union; } } else if ( tp.operations[0].operation == operation_none && tp.operations[1].operation == operation_none ) { // spike not handled by touch<> if ( inters.is_spike_p() ) { tp.operations[0].operation = operation_intersection; tp.operations[1].operation = operation_union; if ( inters.sides().pk_wrt_q2() == 0 ) { tp.operations[0].operation = operation_continue; // will be converted to i tp.operations[0].is_collinear = true; } } } // workarounds for touch<> not taking spikes into account ends here replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); bool ignore_spike = calculate_spike_operation(tp.operations[0].operation, inters, umbrella_strategy.get_point_in_point_strategy()); if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ignore_spike || ! append_opposite_spikes<append_touches>( // for 'i' or 'c' i??? tp, inters, out) ) { *out++ = tp; } } } break; case 'e': { if ( get_turn_info_for_endpoint<true, true>(range_p, range_q, tp_model, inters, method_equal, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { tp.operations[0].is_collinear = true; if ( ! inters.d_info().opposite ) { // Both equal // or collinear-and-ending at intersection point equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); turn_transformer_ec<false> transformer(method_touch); transformer(tp); // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, method_touch, append_equal, out) ) { *out++ = tp; // no spikes } } else { equal_opposite < TurnInfo, AssignPolicy >::apply(range_p, range_q, tp, out, inters); } } } break; case 'c' : { // Collinear if ( get_turn_info_for_endpoint<true, true>( range_p, range_q, tp_model, inters, method_collinear, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { tp.operations[0].is_collinear = true; if ( ! inters.d_info().opposite ) { method_type method_replace = method_touch_interior; append_version_c version = append_collinear; if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); method_replace = method_touch; version = append_equal; } else { collinear<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); //method_replace = method_touch_interior; //version = append_collinear; } turn_transformer_ec<false> transformer(method_replace); transformer(tp); // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, method_replace, version, out) ) { // no spikes *out++ = tp; } } else { // Is this always 'm' ? turn_transformer_ec<false> transformer(method_touch_interior); // conditionally handle spikes if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) { append_opposite_spikes<append_collinear_opposite>( tp, inters, out); } // TODO: ignore for spikes? // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, // the same with is_q_valid collinear_opposite < TurnInfo, AssignPolicy >::apply(range_p, range_q, tp, out, inters, inters.sides(), transformer); } } } break; case '0' : { // degenerate points if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) ) { only_convert::apply(tp, inters.i_info()); if ( range_p.is_first_segment() && equals::equals_point_point(range_p.at(0), tp.point, umbrella_strategy.get_point_in_point_strategy()) ) { tp.operations[0].position = position_front; } else if ( range_p.is_last_segment() && equals::equals_point_point(range_p.at(1), tp.point, umbrella_strategy.get_point_in_point_strategy()) ) { tp.operations[0].position = position_back; } // tp.operations[1].position = position_middle; *out++ = tp; } } break; default : { #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) std::cout << "TURN: Unknown method: " << method << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) BOOST_THROW_EXCEPTION(turn_info_exception(method)); #endif } break; } return out; } template <typename Operation, typename IntersectionInfo, typename EqPPStrategy> static inline bool calculate_spike_operation(Operation & op, IntersectionInfo const& inters, EqPPStrategy const& strategy) { bool is_p_spike = ( op == operation_union || op == operation_intersection ) && inters.is_spike_p(); if ( is_p_spike ) { int const pk_q1 = inters.sides().pk_wrt_q1(); bool going_in = pk_q1 < 0; // Pk on the right bool going_out = pk_q1 > 0; // Pk on the left int const qk_q1 = inters.sides().qk_wrt_q1(); // special cases if ( qk_q1 < 0 ) // Q turning R { // spike on the edge point // if it's already known that the spike is going out this musn't be checked if ( ! going_out && detail::equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) ) { int const pk_q2 = inters.sides().pk_wrt_q2(); going_in = pk_q1 < 0 && pk_q2 < 0; // Pk on the right of both going_out = pk_q1 > 0 || pk_q2 > 0; // Pk on the left of one of them } } else if ( qk_q1 > 0 ) // Q turning L { // spike on the edge point // if it's already known that the spike is going in this musn't be checked if ( ! going_in && detail::equals::equals_point_point(inters.rpj(), inters.rqj(), strategy) ) { int const pk_q2 = inters.sides().pk_wrt_q2(); going_in = pk_q1 < 0 || pk_q2 < 0; // Pk on the right of one of them going_out = pk_q1 > 0 && pk_q2 > 0; // Pk on the left of both } } if ( going_in ) { op = operation_intersection; return true; } else if ( going_out ) { op = operation_union; return true; } } return false; } enum append_version_c { append_equal, append_collinear }; template <typename TurnInfo, typename IntersectionInfo, typename OutIt> static inline bool append_collinear_spikes(TurnInfo & tp, IntersectionInfo const& inters, method_type method, append_version_c version, OutIt out) { // method == touch || touch_interior // both position == middle bool is_p_spike = ( version == append_equal ? ( tp.operations[0].operation == operation_union || tp.operations[0].operation == operation_intersection ) : tp.operations[0].operation == operation_continue ) && inters.is_spike_p(); // TODO: throw an exception for spike in Areal? /*bool is_q_spike = tp.operations[1].operation == operation_continue && inters.is_spike_q(); // both are collinear spikes on the same IP, we can just follow both if ( is_p_spike && is_q_spike ) { return false; } // spike on Linear - it's turning back on the boundary of Areal else*/ if ( is_p_spike ) { tp.method = method; tp.operations[0].operation = operation_blocked; tp.operations[1].operation = operation_union; *out++ = tp; tp.operations[0].operation = operation_continue; // boundary //tp.operations[1].operation = operation_union; *out++ = tp; return true; } // spike on Areal - Linear is going outside /*else if ( is_q_spike ) { tp.method = method; tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_continue; *out++ = tp; *out++ = tp; return true; }*/ return false; } enum append_version_o { append_touches, append_collinear_opposite }; template <append_version_o Version, typename TurnInfo, typename IntersectionInfo, typename OutIt> static inline bool append_opposite_spikes(TurnInfo & tp, IntersectionInfo const& inters, OutIt out) { static const bool is_version_touches = (Version == append_touches); bool is_p_spike = ( is_version_touches ? ( tp.operations[0].operation == operation_continue || tp.operations[0].operation == operation_intersection ) : // i ??? true ) && inters.is_spike_p(); // TODO: throw an exception for spike in Areal? /*bool is_q_spike = ( ( Version == append_touches && tp.operations[1].operation == operation_continue ) || ( Version == append_collinear_opposite && tp.operations[1].operation == operation_none ) ) && inters.is_spike_q(); if ( is_p_spike && is_q_spike ) { // u/u or nothing? return false; } else*/ if ( is_p_spike ) { if ( BOOST_GEOMETRY_CONDITION(is_version_touches) || inters.d_info().arrival[0] == 1 ) { if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) { tp.operations[0].is_collinear = true; //tp.operations[1].is_collinear = false; tp.method = method_touch; } else { tp.operations[0].is_collinear = true; //tp.operations[1].is_collinear = false; BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1); base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); } tp.operations[0].operation = operation_blocked; tp.operations[1].operation = operation_continue; // boundary *out++ = tp; tp.operations[0].operation = operation_continue; // boundary //tp.operations[1].operation = operation_continue; // boundary *out++ = tp; return true; } } /*else if ( is_q_spike ) { tp.operations[0].is_collinear = true; tp.method = is_version_touches ? method_touch : method_touch_interior; tp.operations[0].operation = operation_continue; tp.operations[1].operation = operation_continue; // boundary *out++ = tp; *out++ = tp; return true; }*/ return false; } static inline void replace_method_and_operations_tm(method_type & method, operation_type & op0, operation_type & op1) { if ( op0 == operation_blocked && op1 == operation_blocked ) { // NOTE: probably only if methods are WRT IPs, not segments! method = (method == method_touch ? method_equal : method_collinear); } // Assuming G1 is always Linear if ( op0 == operation_blocked ) { op0 = operation_continue; } if ( op1 == operation_blocked ) { op1 = operation_continue; } else if ( op1 == operation_intersection ) { op1 = operation_union; } // spikes in 'm' if ( method == method_error ) { method = method_touch_interior; op0 = operation_union; op1 = operation_union; } } template <bool IsFront> class turn_transformer_ec { public: explicit turn_transformer_ec(method_type method_t_or_m) : m_method(method_t_or_m) {} template <typename Turn> void operator()(Turn & turn) const { operation_type & op0 = turn.operations[0].operation; operation_type & op1 = turn.operations[1].operation; // NOTE: probably only if methods are WRT IPs, not segments! if ( BOOST_GEOMETRY_CONDITION(IsFront) || op0 == operation_intersection || op0 == operation_union || op1 == operation_intersection || op1 == operation_union ) { turn.method = m_method; } turn.operations[0].is_collinear = op0 != operation_blocked; // Assuming G1 is always Linear if ( op0 == operation_blocked ) { op0 = operation_continue; } if ( op1 == operation_blocked ) { op1 = operation_continue; } else if ( op1 == operation_intersection ) { op1 = operation_union; } } private: method_type m_method; }; static inline void replace_operations_i(operation_type & /*op0*/, operation_type & op1) { // assuming Linear is always the first one op1 = operation_union; } // NOTE: Spikes may NOT be handled for Linear endpoints because it's not // possible to define a spike on an endpoint. Areal geometries must // NOT have spikes at all. One thing that could be done is to throw // an exception when spike is detected in Areal geometry. template <bool EnableFirst, bool EnableLast, typename UniqueSubRange1, typename UniqueSubRange2, typename TurnInfo, typename IntersectionInfo, typename OutputIterator, typename EqPPStrategy> static inline bool get_turn_info_for_endpoint( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo const& tp_model, IntersectionInfo const& inters, method_type /*method*/, OutputIterator out, EqPPStrategy const& strategy) { namespace ov = overlay; typedef ov::get_turn_info_for_endpoint<EnableFirst, EnableLast> get_info_e; const std::size_t ip_count = inters.i_info().count; // no intersection points if (ip_count == 0) { return false; } if (! range_p.is_first_segment() && ! range_p.is_last_segment()) { // P sub-range has no end-points return false; } typename IntersectionInfo::side_strategy_type const& sides = inters.get_side_strategy(); linear_intersections intersections(range_p.at(0), range_q.at(0), inters.result(), range_p.is_last_segment(), range_q.is_last_segment(), strategy); linear_intersections::ip_info const& ip0 = intersections.template get<0>(); linear_intersections::ip_info const& ip1 = intersections.template get<1>(); const bool opposite = inters.d_info().opposite; // ANALYSE AND ASSIGN FIRST // IP on the first point of Linear Geometry bool was_first_point_handled = false; if ( BOOST_GEOMETRY_CONDITION(EnableFirst) && range_p.is_first_segment() && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication { TurnInfo tp = tp_model; tp.operations[0].position = position_front; tp.operations[1].position = position_middle; if ( opposite ) // opposite -> collinear { tp.operations[0].operation = operation_continue; tp.operations[1].operation = operation_union; tp.method = ip0.is_qj ? method_touch : method_touch_interior; } else { // pi is the intersection point at qj or in the middle of q1 // so consider segments // 1. pi at qj: qi-qj-pj and qi-qj-qk // x: qi-qj, y: qj-qk, qz: qk // 2. pi in the middle of q1: qi-pi-pj and qi-pi-qj // x: qi-pi, y: pi-qj, qz: qj // qi-pi, side the same as WRT q1 // pi-qj, side the same as WRT q1 // qj WRT q1 is 0 method_type replaced_method = method_none; int side_pj_y = 0, side_pj_x = 0, side_qz_x = 0; // 1. ip0 or pi at qj if ( ip0.is_qj ) { replaced_method = method_touch; side_pj_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(1)); // pj wrt q2 side_pj_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(1)); // pj wrt q1 side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1 } // 2. ip0 or pi in the middle of q1 else { replaced_method = method_touch_interior; side_pj_y = sides.apply(range_q.at(0), range_q.at(1), range_p.at(1)); // pj wrt q1 side_pj_x = side_pj_y; // pj wrt q1 side_qz_x = 0; // qj wrt q1 } std::pair<operation_type, operation_type> operations = get_info_e::operations_of_equal(side_pj_y, side_pj_x, side_qz_x); tp.operations[0].operation = operations.first; tp.operations[1].operation = operations.second; turn_transformer_ec<true> transformer(replaced_method); transformer(tp); } // equals<> or collinear<> will assign the second point, // we'd like to assign the first one base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0); // NOTE: is_collinear is not set for the first endpoint of L // for which there is no preceding segment // here is_p_first_ip == true tp.operations[0].is_collinear = false; *out++ = tp; was_first_point_handled = true; } // ANALYSE AND ASSIGN LAST // IP on the last point of Linear Geometry if ( BOOST_GEOMETRY_CONDITION(EnableLast) && range_p.is_last_segment() && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication { TurnInfo tp = tp_model; if ( inters.i_info().count > 1 ) { //BOOST_GEOMETRY_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 ); tp.operations[0].is_collinear = true; tp.operations[1].operation = opposite ? operation_continue : operation_union; } else //if ( result.template get<0>().count == 1 ) { // pj is the intersection point at qj or in the middle of q1 // so consider segments // 1. pj at qj: qi-qj-pi and qi-qj-qk // x: qi-qj, y: qj-qk, qz: qk // 2. pj in the middle of q1: qi-pj-pi and qi-pj-qj // x: qi-pj, y: pj-qj, qz: qj // qi-pj, the side is the same as WRT q1 // pj-qj, the side is the same as WRT q1 // side of qj WRT q1 is 0 int side_pi_y = 0, side_pi_x = 0, side_qz_x = 0; // 1. ip0 or pj at qj if ( ip0.is_qj ) { side_pi_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(0)); // pi wrt q2 side_pi_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1 side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1 } // 2. ip0 or pj in the middle of q1 else { side_pi_y = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1 side_pi_x = side_pi_y; // pi wrt q1 side_qz_x = 0; // qj wrt q1 } std::pair<operation_type, operation_type> operations = get_info_e::operations_of_equal(side_pi_y, side_pi_x, side_qz_x); tp.operations[0].operation = operations.first; tp.operations[1].operation = operations.second; turn_transformer_ec<false> transformer(method_none); transformer(tp); tp.operations[0].is_collinear = tp.both(operation_continue); } tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior; tp.operations[0].operation = operation_blocked; tp.operations[0].position = position_back; tp.operations[1].position = position_middle; // equals<> or collinear<> will assign the second point, // we'd like to assign the first one unsigned int ip_index = ip_count > 1 ? 1 : 0; base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index); *out++ = tp; // don't ignore the first IP if the segment is opposite return !( opposite && ip_count > 1 ) || was_first_point_handled; } // don't ignore anything for now return false; } template <typename Point1, typename Point2, typename IntersectionStrategy> static inline bool equals_point_point(Point1 const& point1, Point2 const& point2, IntersectionStrategy const& strategy) { return detail::equals::equals_point_point(point1, point2, strategy.get_point_in_point_strategy()); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LA_HPP detail/overlay/assign_parents.hpp 0000644 00000034672 15125631657 0013247 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/expand.hpp> #include <boost/geometry/algorithms/detail/partition.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/geometries/box.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < typename Item, typename InnerGeometry, typename Geometry1, typename Geometry2, typename RingCollection, typename Strategy > static inline bool within_selected_input(Item const& item2, InnerGeometry const& inner_geometry, ring_identifier const& outer_id, Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection, Strategy const& strategy) { typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; // NOTE: range_in_geometry first checks the item2.point and then // if this point is on boundary it checks points of inner_geometry // ring until a point inside/outside other geometry ring is found switch (outer_id.source_index) { // covered_by case 0 : return range_in_geometry(item2.point, inner_geometry, get_ring<tag1>::apply(outer_id, geometry1), strategy) >= 0; case 1 : return range_in_geometry(item2.point, inner_geometry, get_ring<tag2>::apply(outer_id, geometry2), strategy) >= 0; case 2 : return range_in_geometry(item2.point, inner_geometry, get_ring<void>::apply(outer_id, collection), strategy) >= 0; } return false; } template < typename Item, typename Geometry1, typename Geometry2, typename RingCollection, typename Strategy > static inline bool within_selected_input(Item const& item2, ring_identifier const& inner_id, ring_identifier const& outer_id, Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection, Strategy const& strategy) { typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; switch (inner_id.source_index) { case 0 : return within_selected_input(item2, get_ring<tag1>::apply(inner_id, geometry1), outer_id, geometry1, geometry2, collection, strategy); case 1 : return within_selected_input(item2, get_ring<tag2>::apply(inner_id, geometry2), outer_id, geometry1, geometry2, collection, strategy); case 2 : return within_selected_input(item2, get_ring<void>::apply(inner_id, collection), outer_id, geometry1, geometry2, collection, strategy); } return false; } template <typename Point, typename AreaType> struct ring_info_helper { ring_identifier id; AreaType real_area; AreaType abs_area; model::box<Point> envelope; inline ring_info_helper() : real_area(0), abs_area(0) {} inline ring_info_helper(ring_identifier i, AreaType const& a) : id(i), real_area(a), abs_area(geometry::math::abs(a)) {} }; template <typename BoxExpandStrategy> struct ring_info_helper_get_box { template <typename Box, typename InputItem> static inline void apply(Box& total, InputItem const& item) { assert_coordinate_type_equal(total, item.envelope); geometry::expand(total, item.envelope, BoxExpandStrategy()); } }; template <typename DisjointBoxBoxStrategy> struct ring_info_helper_overlaps_box { template <typename Box, typename InputItem> static inline bool apply(Box const& box, InputItem const& item) { assert_coordinate_type_equal(box, item.envelope); return ! geometry::detail::disjoint::disjoint_box_box( box, item.envelope, DisjointBoxBoxStrategy()); } }; // Segments intersection Strategy template < typename Geometry1, typename Geometry2, typename Collection, typename RingMap, typename Strategy > struct assign_visitor { typedef typename RingMap::mapped_type ring_info_type; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; Collection const& m_collection; RingMap& m_ring_map; Strategy const& m_strategy; bool m_check_for_orientation; inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c, RingMap& map, Strategy const& strategy, bool check) : m_geometry1(g1) , m_geometry2(g2) , m_collection(c) , m_ring_map(map) , m_strategy(strategy) , m_check_for_orientation(check) {} template <typename Item> inline bool apply(Item const& outer, Item const& inner, bool first = true) { if (first && outer.abs_area < inner.abs_area) { // Apply with reversed arguments apply(inner, outer, false); return true; } if (m_check_for_orientation || (math::larger(outer.real_area, 0) && math::smaller(inner.real_area, 0))) { ring_info_type& inner_in_map = m_ring_map[inner.id]; if (geometry::covered_by(inner_in_map.point, outer.envelope, typename Strategy::disjoint_point_box_strategy_type()) && within_selected_input(inner_in_map, inner.id, outer.id, m_geometry1, m_geometry2, m_collection, m_strategy) ) { // Assign a parent if there was no earlier parent, or the newly // found parent is smaller than the previous one if (inner_in_map.parent.source_index == -1 || outer.abs_area < inner_in_map.parent_area) { inner_in_map.parent = outer.id; inner_in_map.parent_area = outer.abs_area; } } } return true; } }; template < overlay_type OverlayType, typename Geometry1, typename Geometry2, typename RingCollection, typename RingMap, typename Strategy > inline void assign_parents(Geometry1 const& geometry1, Geometry2 const& geometry2, RingCollection const& collection, RingMap& ring_map, Strategy const& strategy) { static bool const is_difference = OverlayType == overlay_difference; static bool const is_buffer = OverlayType == overlay_buffer; static bool const is_dissolve = OverlayType == overlay_dissolve; static bool const check_for_orientation = is_buffer || is_dissolve; typedef typename geometry::tag<Geometry1>::type tag1; typedef typename geometry::tag<Geometry2>::type tag2; typedef typename RingMap::mapped_type ring_info_type; typedef typename ring_info_type::point_type point_type; typedef model::box<point_type> box_type; typedef typename Strategy::template area_strategy < point_type >::type::template result_type<point_type>::type area_result_type; typedef typename RingMap::iterator map_iterator_type; { typedef ring_info_helper<point_type, area_result_type> helper; typedef std::vector<helper> vector_type; typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type; std::size_t count_total = ring_map.size(); std::size_t count_positive = 0; std::size_t index_positive = 0; // only used if count_positive>0 std::size_t index = 0; // Copy to vector (with new approach this might be obsolete as well, using the map directly) vector_type vector(count_total); for (map_iterator_type it = boost::begin(ring_map); it != boost::end(ring_map); ++it, ++index) { vector[index] = helper(it->first, it->second.get_area()); helper& item = vector[index]; switch(it->first.source_index) { case 0 : geometry::envelope(get_ring<tag1>::apply(it->first, geometry1), item.envelope, strategy.get_envelope_strategy()); break; case 1 : geometry::envelope(get_ring<tag2>::apply(it->first, geometry2), item.envelope, strategy.get_envelope_strategy()); break; case 2 : geometry::envelope(get_ring<void>::apply(it->first, collection), item.envelope, strategy.get_envelope_strategy()); break; } // Expand envelope slightly expand_by_epsilon(item.envelope); if (item.real_area > 0) { count_positive++; index_positive = index; } } if (! check_for_orientation) { if (count_positive == count_total) { // Optimization for only positive rings // -> no assignment of parents or reversal necessary, ready here. return; } if (count_positive == 1 && ! is_difference && ! is_dissolve) { // Optimization for one outer ring // -> assign this as parent to all others (all interior rings) // In unions, this is probably the most occuring case and gives // a dramatic improvement (factor 5 for star_comb testcase) // In difference or other cases where interior rings might be // located outside the outer ring, this cannot be done ring_identifier id_of_positive = vector[index_positive].id; ring_info_type& outer = ring_map[id_of_positive]; index = 0; for (vector_iterator_type it = boost::begin(vector); it != boost::end(vector); ++it, ++index) { if (index != index_positive) { ring_info_type& inner = ring_map[it->id]; inner.parent = id_of_positive; outer.children.push_back(it->id); } } return; } } assign_visitor < Geometry1, Geometry2, RingCollection, RingMap, Strategy > visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation); typedef ring_info_helper_get_box < typename Strategy::expand_box_strategy_type > expand_box_type; typedef ring_info_helper_overlaps_box < typename Strategy::disjoint_box_box_strategy_type > overlaps_box_type; geometry::partition < box_type >::apply(vector, visitor, expand_box_type(), overlaps_box_type()); } if (check_for_orientation) { for (map_iterator_type it = boost::begin(ring_map); it != boost::end(ring_map); ++it) { ring_info_type& info = it->second; if (geometry::math::equals(info.get_area(), 0)) { info.discarded = true; } else if (info.parent.source_index >= 0) { const ring_info_type& parent = ring_map[info.parent]; bool const pos = math::larger(info.get_area(), 0); bool const parent_pos = math::larger(parent.area, 0); bool const double_neg = is_dissolve && ! pos && ! parent_pos; if ((pos && parent_pos) || double_neg) { // Discard positive inner ring with positive parent // Also, for some cases (dissolve), negative inner ring // with negative parent should be discarded info.discarded = true; } if (pos || info.discarded) { // Remove parent ID from any positive or discarded inner rings info.parent.source_index = -1; } } else if (info.parent.source_index < 0 && math::smaller(info.get_area(), 0)) { // Reverse negative ring without parent info.reversed = true; } } } // Assign childlist for (map_iterator_type it = boost::begin(ring_map); it != boost::end(ring_map); ++it) { if (it->second.parent.source_index >= 0) { ring_map[it->second.parent].children.push_back(it->first); } } } // Version for one geometry (called by buffer/dissolve) template < overlay_type OverlayType, typename Geometry, typename RingCollection, typename RingMap, typename Strategy > inline void assign_parents(Geometry const& geometry, RingCollection const& collection, RingMap& ring_map, Strategy const& strategy) { // Call it with an empty geometry as second geometry (source_id == 1) // (ring_map should be empty for source_id==1) Geometry empty; assign_parents<OverlayType>(geometry, empty, collection, ring_map, strategy); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP detail/overlay/enrich_intersection_points.hpp 0000644 00000045221 15125631657 0015651 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP #include <cstddef> #include <algorithm> #include <map> #include <set> #include <vector> #ifdef BOOST_GEOMETRY_DEBUG_ENRICH # include <iostream> # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> # include <boost/geometry/io/wkt/wkt.hpp> # if ! defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER) # define BOOST_GEOMETRY_DEBUG_IDENTIFIER #endif #endif #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp> #include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/policies/robustness/robust_type.hpp> #ifdef BOOST_GEOMETRY_DEBUG_ENRICH # include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Turns> struct discarded_indexed_turn { discarded_indexed_turn(Turns const& turns) : m_turns(turns) {} template <typename IndexedTurn> inline bool operator()(IndexedTurn const& indexed) const { return m_turns[indexed.turn_index].discarded; } Turns const& m_turns; }; // Sorts IP-s of this ring on segment-identifier, and if on same segment, // on distance. // Then assigns for each IP which is the next IP on this segment, // plus the vertex-index to travel to, plus the next IP // (might be on another segment) template < bool Reverse1, bool Reverse2, typename Operations, typename Turns, typename Geometry1, typename Geometry2, typename RobustPolicy, typename SideStrategy > inline void enrich_sort(Operations& operations, Turns const& turns, Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, SideStrategy const& strategy) { std::sort(boost::begin(operations), boost::end(operations), less_by_segment_ratio < Turns, typename boost::range_value<Operations>::type, Geometry1, Geometry2, RobustPolicy, SideStrategy, Reverse1, Reverse2 >(turns, geometry1, geometry2, robust_policy, strategy)); } template <typename Operations, typename Turns> inline void enrich_assign(Operations& operations, Turns& turns, bool check_turns) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type op_type; typedef typename boost::range_iterator<Operations>::type iterator_type; if (operations.size() > 0) { // Assign travel-to-vertex/ip index for each turning point. // Iterator "next" is circular geometry::ever_circling_range_iterator<Operations const> next(operations); ++next; for (iterator_type it = boost::begin(operations); it != boost::end(operations); ++it) { turn_type& turn = turns[it->turn_index]; op_type& op = turn.operations[it->operation_index]; if (check_turns && it->turn_index == next->turn_index) { // Normal behaviour: next points at next turn, increase next. // For dissolve this should not be done, turn_index is often // the same for two consecutive operations ++next; } // Cluster behaviour: next should point after cluster, unless // their seg_ids are not the same // (For dissolve, this is still to be examined - TODO) while (turn.is_clustered() && it->turn_index != next->turn_index && turn.cluster_id == turns[next->turn_index].cluster_id && op.seg_id == turns[next->turn_index].operations[next->operation_index].seg_id) { ++next; } turn_type const& next_turn = turns[next->turn_index]; op_type const& next_op = next_turn.operations[next->operation_index]; op.enriched.travels_to_ip_index = static_cast<signed_size_type>(next->turn_index); op.enriched.travels_to_vertex_index = next->subject->seg_id.segment_index; if (op.seg_id.segment_index == next_op.seg_id.segment_index && op.fraction < next_op.fraction) { // Next turn is located further on same segment // assign next_ip_index // (this is one not circular therefore fraction is considered) op.enriched.next_ip_index = static_cast<signed_size_type>(next->turn_index); } if (! check_turns) { ++next; } } } // DEBUG #ifdef BOOST_GEOMETRY_DEBUG_ENRICH { for (iterator_type it = boost::begin(operations); it != boost::end(operations); ++it) { op_type const& op = turns[it->turn_index] .operations[it->operation_index]; std::cout << it->turn_index << " cl=" << turns[it->turn_index].cluster_id << " meth=" << method_char(turns[it->turn_index].method) << " seg=" << op.seg_id << " dst=" << op.fraction // needs define << " op=" << operation_char(turns[it->turn_index].operations[0].operation) << operation_char(turns[it->turn_index].operations[1].operation) << " (" << operation_char(op.operation) << ")" << " nxt=" << op.enriched.next_ip_index << " / " << op.enriched.travels_to_ip_index << " [vx " << op.enriched.travels_to_vertex_index << "]" << std::boolalpha << turns[it->turn_index].discarded << std::endl; ; } } #endif // END DEBUG } template <typename Operations, typename Turns> inline void enrich_adapt(Operations& operations, Turns& turns) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type op_type; typedef typename boost::range_value<Operations>::type indexed_turn_type; if (operations.size() < 3) { // If it is empty, or contains one or two turns, it makes no sense return; } // Operations is a vector of indexed_turn_operation<> // Last index: std::size_t const x = operations.size() - 1; bool next_phase = false; for (std::size_t i = 0; i < operations.size(); i++) { indexed_turn_type const& indexed = operations[i]; turn_type& turn = turns[indexed.turn_index]; op_type& op = turn.operations[indexed.operation_index]; // Previous/next index std::size_t const p = i > 0 ? i - 1 : x; std::size_t const n = i < x ? i + 1 : 0; turn_type const& next_turn = turns[operations[n].turn_index]; op_type const& next_op = next_turn.operations[operations[n].operation_index]; if (op.seg_id.segment_index == next_op.seg_id.segment_index) { turn_type const& prev_turn = turns[operations[p].turn_index]; op_type const& prev_op = prev_turn.operations[operations[p].operation_index]; if (op.seg_id.segment_index == prev_op.seg_id.segment_index) { op.enriched.startable = false; next_phase = true; } } } if (! next_phase) { return; } // Discard turns which are both non-startable next_phase = false; for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type& turn = *it; if (! turn.operations[0].enriched.startable && ! turn.operations[1].enriched.startable) { turn.discarded = true; next_phase = true; } } if (! next_phase) { return; } // Remove discarded turns from operations to avoid having them as next turn discarded_indexed_turn<Turns> const predicate(turns); operations.erase(std::remove_if(boost::begin(operations), boost::end(operations), predicate), boost::end(operations)); } struct enriched_map_default_include_policy { template <typename Operation> static inline bool include(Operation const& ) { // By default include all operations return true; } }; template <typename Turns, typename MappedVector, typename IncludePolicy> inline void create_map(Turns const& turns, MappedVector& mapped_vector, IncludePolicy const& include_policy) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::container_type container_type; typedef typename MappedVector::mapped_type mapped_type; typedef typename boost::range_value<mapped_type>::type indexed_type; std::size_t index = 0; for (typename boost::range_iterator<Turns const>::type it = boost::begin(turns); it != boost::end(turns); ++it, ++index) { // Add all (non discarded) operations on this ring // Blocked operations or uu on clusters (for intersection) // should be included, to block potential paths in clusters turn_type const& turn = *it; if (turn.discarded) { continue; } std::size_t op_index = 0; for (typename boost::range_iterator<container_type const>::type op_it = boost::begin(turn.operations); op_it != boost::end(turn.operations); ++op_it, ++op_index) { if (include_policy.include(op_it->operation)) { ring_identifier const ring_id ( op_it->seg_id.source_index, op_it->seg_id.multi_index, op_it->seg_id.ring_index ); mapped_vector[ring_id].push_back ( indexed_type(index, op_index, *op_it, it->operations[1 - op_index].seg_id) ); } } } } template <typename Point1, typename Point2> inline typename geometry::coordinate_type<Point1>::type distance_measure(Point1 const& a, Point2 const& b) { // TODO: use comparable distance for point-point instead - but that // causes currently cycling include problems typedef typename geometry::coordinate_type<Point1>::type ctype; ctype const dx = get<0>(a) - get<0>(b); ctype const dy = get<1>(a) - get<1>(b); return dx * dx + dy * dy; } template <typename Turns> inline void calculate_remaining_distance(Turns& turns) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type op_type; for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type& turn = *it; op_type& op0 = turn.operations[0]; op_type& op1 = turn.operations[1]; if (op0.remaining_distance != 0 || op1.remaining_distance != 0) { continue; } signed_size_type const to_index0 = op0.enriched.get_next_turn_index(); signed_size_type const to_index1 = op1.enriched.get_next_turn_index(); if (to_index0 >= 0 && to_index1 >= 0 && to_index0 != to_index1) { op0.remaining_distance = distance_measure(turn.point, turns[to_index0].point); op1.remaining_distance = distance_measure(turn.point, turns[to_index1].point); } } } }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL /*! \brief All intersection points are enriched with successor information \ingroup overlay \tparam Turns type of intersection container (e.g. vector of "intersection/turn point"'s) \tparam Clusters type of cluster container \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam PointInGeometryStrategy point in geometry strategy type \param turns container containing intersection points \param clusters container containing clusters \param geometry1 \param_geometry \param geometry2 \param_geometry \param robust_policy policy to handle robustness issues \param strategy point in geometry strategy */ template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Turns, typename Clusters, typename Geometry1, typename Geometry2, typename RobustPolicy, typename IntersectionStrategy > inline void enrich_intersection_points(Turns& turns, Clusters& clusters, Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, IntersectionStrategy const& strategy) { static const detail::overlay::operation_type target_operation = detail::overlay::operation_from_overlay<OverlayType>::value; static const detail::overlay::operation_type opposite_operation = target_operation == detail::overlay::operation_union ? detail::overlay::operation_intersection : detail::overlay::operation_union; static const bool is_dissolve = OverlayType == overlay_dissolve; typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type op_type; typedef detail::overlay::indexed_turn_operation < op_type > indexed_turn_operation; typedef std::map < ring_identifier, std::vector<indexed_turn_operation> > mapped_vector_type; // From here on, turn indexes are used (in clusters, next_index, etc) // and may only be flagged as discarded bool has_cc = false; bool const has_colocations = detail::overlay::handle_colocations<Reverse1, Reverse2, OverlayType>(turns, clusters, geometry1, geometry2); // Discard turns not part of target overlay for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type& turn = *it; if (turn.both(detail::overlay::operation_none) || turn.both(opposite_operation) || turn.both(detail::overlay::operation_blocked) || (detail::overlay::is_self_turn<OverlayType>(turn) && ! turn.is_clustered() && ! turn.both(target_operation))) { // For all operations, discard xx and none/none // For intersections, remove uu to avoid the need to travel // a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33) // The ux is necessary to indicate impossible paths // (especially if rescaling is removed) // Similarly, for union, discard ii and ix // For self-turns, only keep uu / ii turn.discarded = true; turn.cluster_id = -1; continue; } if (! turn.discarded && turn.both(detail::overlay::operation_continue)) { has_cc = true; } } if (! is_dissolve) { detail::overlay::discard_closed_turns < OverlayType, target_operation >::apply(turns, clusters, geometry1, geometry2, strategy); detail::overlay::discard_open_turns < OverlayType, target_operation >::apply(turns, clusters, geometry1, geometry2, strategy); } // Create a map of vectors of indexed operation-types to be able // to sort intersection points PER RING mapped_vector_type mapped_vector; detail::overlay::create_map(turns, mapped_vector, detail::overlay::enriched_map_default_include_policy()); // No const-iterator; contents of mapped copy is temporary, // and changed by enrich for (typename mapped_vector_type::iterator mit = mapped_vector.begin(); mit != mapped_vector.end(); ++mit) { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout << "ENRICH-sort Ring " << mit->first << std::endl; #endif detail::overlay::enrich_sort<Reverse1, Reverse2>( mit->second, turns, geometry1, geometry2, robust_policy, strategy.get_side_strategy()); } for (typename mapped_vector_type::iterator mit = mapped_vector.begin(); mit != mapped_vector.end(); ++mit) { #ifdef BOOST_GEOMETRY_DEBUG_ENRICH std::cout << "ENRICH-assign Ring " << mit->first << std::endl; #endif if (is_dissolve) { detail::overlay::enrich_adapt(mit->second, turns); } detail::overlay::enrich_assign(mit->second, turns, ! is_dissolve); } if (has_colocations) { // First gather cluster properties (using even clusters with // discarded turns - for open turns), then clean up clusters detail::overlay::gather_cluster_properties < Reverse1, Reverse2, OverlayType >(clusters, turns, target_operation, geometry1, geometry2, strategy.get_side_strategy()); detail::overlay::cleanup_clusters(turns, clusters); } if (has_cc) { detail::overlay::calculate_remaining_distance(turns); } #ifdef BOOST_GEOMETRY_DEBUG_ENRICH //detail::overlay::check_graph(turns, for_operation); #endif } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP detail/overlay/less_by_segment_ratio.hpp 0000644 00000014112 15125631657 0014572 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_ON_SEGMENT_RATIO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_ON_SEGMENT_RATIO_HPP #include <cstddef> #include <algorithm> #include <map> #include <set> #include <vector> #include <boost/core/addressof.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp> #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp> #include <boost/geometry/strategies/side.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // Wraps "turn_operation" from turn_info.hpp, // giving it extra information, necessary for sorting template <typename TurnOperation> struct indexed_turn_operation { typedef TurnOperation type; std::size_t turn_index; std::size_t operation_index; bool skip; // use pointers to avoid copies, const& is not possible because of usage in vector segment_identifier const* other_seg_id; // segment id of other segment of intersection of two segments TurnOperation const* subject; inline indexed_turn_operation(std::size_t ti, std::size_t oi, TurnOperation const& sub, segment_identifier const& oid) : turn_index(ti) , operation_index(oi) , skip(false) , other_seg_id(&oid) , subject(boost::addressof(sub)) {} }; template < typename Turns, typename Indexed, typename Geometry1, typename Geometry2, typename RobustPolicy, typename SideStrategy, bool Reverse1, bool Reverse2 > struct less_by_segment_ratio { inline less_by_segment_ratio(Turns const& turns , Geometry1 const& geometry1 , Geometry2 const& geometry2 , RobustPolicy const& robust_policy , SideStrategy const& strategy) : m_turns(turns) , m_geometry1(geometry1) , m_geometry2(geometry2) , m_robust_policy(robust_policy) , m_strategy(strategy) { } private : Turns const& m_turns; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; RobustPolicy const& m_robust_policy; SideStrategy const& m_strategy; typedef typename geometry::point_type<Geometry1>::type point_type; inline bool default_order(Indexed const& left, Indexed const& right) const { // We've nothing to sort on. Take the indexes return left.turn_index < right.turn_index; } inline bool consider_relative_order(Indexed const& left, Indexed const& right) const { point_type pi, pj, ri, rj, si, sj; geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2, left.subject->seg_id, pi, pj); geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2, *left.other_seg_id, ri, rj); geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2, *right.other_seg_id, si, sj); int const side_rj_p = m_strategy.apply(pi, pj, rj); int const side_sj_p = m_strategy.apply(pi, pj, sj); // Put the one turning left (1; right == -1) as last if (side_rj_p != side_sj_p) { return side_rj_p < side_sj_p; } int const side_sj_r = m_strategy.apply(ri, rj, sj); int const side_rj_s = m_strategy.apply(si, sj, rj); // If they both turn left: the most left as last // If they both turn right: this is not relevant, but take also here most left if (side_rj_s != side_sj_r) { return side_rj_s < side_sj_r; } return default_order(left, right); } public : // Note that left/right do NOT correspond to m_geometry1/m_geometry2 // but to the "indexed_turn_operation" inline bool operator()(Indexed const& left, Indexed const& right) const { if (! (left.subject->seg_id == right.subject->seg_id)) { return left.subject->seg_id < right.subject->seg_id; } // Both left and right are located on the SAME segment. if (! (left.subject->fraction == right.subject->fraction)) { return left.subject->fraction < right.subject->fraction; } typedef typename boost::range_value<Turns>::type turn_type; turn_type const& left_turn = m_turns[left.turn_index]; turn_type const& right_turn = m_turns[right.turn_index]; // First check "real" intersection (crosses) // -> distance zero due to precision, solve it by sorting if (left_turn.method == method_crosses && right_turn.method == method_crosses) { return consider_relative_order(left, right); } bool const left_both_xx = left_turn.both(operation_blocked); bool const right_both_xx = right_turn.both(operation_blocked); if (left_both_xx && ! right_both_xx) { return true; } if (! left_both_xx && right_both_xx) { return false; } bool const left_both_uu = left_turn.both(operation_union); bool const right_both_uu = right_turn.both(operation_union); if (left_both_uu && ! right_both_uu) { return true; } if (! left_both_uu && right_both_uu) { return false; } return default_order(left, right); } }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_ON_SEGMENT_RATIO_HPP detail/overlay/backtrack_check_si.hpp 0000644 00000014470 15125631657 0013776 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP #include <cstddef> #include <string> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/has_self_intersections.hpp> #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> # include <boost/geometry/io/wkt/wkt.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Turns> inline void clear_visit_info(Turns& turns) { typedef typename boost::range_value<Turns>::type tp_type; for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { for (typename boost::range_iterator < typename tp_type::container_type >::type op_it = boost::begin(it->operations); op_it != boost::end(it->operations); ++op_it) { op_it->visited.clear(); } } } struct backtrack_state { bool m_good; inline backtrack_state() : m_good(true) {} inline void reset() { m_good = true; } inline bool good() const { return m_good; } }; enum traverse_error_type { traverse_error_none, traverse_error_no_next_ip_at_start, traverse_error_no_next_ip, traverse_error_dead_end_at_start, traverse_error_dead_end, traverse_error_visit_again, traverse_error_endless_loop }; inline std::string traverse_error_string(traverse_error_type error) { switch (error) { case traverse_error_none : return ""; case traverse_error_no_next_ip_at_start : return "No next IP at start"; case traverse_error_no_next_ip : return "No next IP"; case traverse_error_dead_end_at_start : return "Dead end at start"; case traverse_error_dead_end : return "Dead end"; case traverse_error_visit_again : return "Visit again"; case traverse_error_endless_loop : return "Endless loop"; default : return ""; } return ""; } template < typename Geometry1, typename Geometry2 > class backtrack_check_self_intersections { struct state : public backtrack_state { bool m_checked; inline state() : m_checked(true) {} }; public : typedef state state_type; template < typename Operation, typename Rings, typename Ring, typename Turns, typename Strategy, typename RobustPolicy, typename Visitor > static inline void apply(std::size_t size_at_start, Rings& rings, Ring& ring, Turns& turns, typename boost::range_value<Turns>::type const& turn, Operation& operation, traverse_error_type traverse_error, Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy, RobustPolicy const& robust_policy, state_type& state, Visitor& visitor) { visitor.visit_traverse_reject(turns, turn, operation, traverse_error); state.m_good = false; // Check self-intersections and throw exception if appropriate if (! state.m_checked) { state.m_checked = true; has_self_intersections(geometry1, strategy, robust_policy); has_self_intersections(geometry2, strategy, robust_policy); } // Make bad output clean rings.resize(size_at_start); geometry::traits::clear<typename boost::range_value<Rings>::type>::apply(ring); // Reject this as a starting point operation.visited.set_rejected(); // And clear all visit info clear_visit_info(turns); } }; #ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT template < typename Geometry1, typename Geometry2 > class backtrack_debug { public : typedef backtrack_state state_type; template <typename Operation, typename Rings, typename Turns> static inline void apply(std::size_t size_at_start, Rings& rings, typename boost::range_value<Rings>::type& ring, Turns& turns, Operation& operation, std::string const& reason, Geometry1 const& geometry1, Geometry2 const& geometry2, state_type& state ) { std::cout << " REJECT " << reason << std::endl; state.m_good = false; rings.resize(size_at_start); ring.clear(); operation.visited.set_rejected(); clear_visit_info(turns); int c = 0; for (int i = 0; i < turns.size(); i++) { for (int j = 0; j < 2; j++) { if (turns[i].operations[j].visited.rejected()) { c++; } } } std::cout << "BACKTRACK (" << reason << " )" << " " << c << " of " << turns.size() << " rejected" << std::endl; std::cout << geometry::wkt(geometry1) << std::endl << geometry::wkt(geometry2) << std::endl; } }; #endif // BOOST_GEOMETRY_OVERLAY_REPORT_WKT }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP detail/overlay/visit_info.hpp 0000644 00000004456 15125631657 0012375 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { class visit_info { private : static const int NONE = 0; static const int STARTED = 1; static const int VISITED = 2; static const int FINISHED = 3; static const int REJECTED = 4; int m_visit_code; bool m_rejected; bool m_final; public: inline visit_info() : m_visit_code(0) , m_rejected(false) , m_final(false) {} inline void set_visited() { m_visit_code = VISITED; } inline void set_started() { m_visit_code = STARTED; } inline void set_finished() { m_visit_code = FINISHED; } inline void set_rejected() { m_visit_code = REJECTED; m_rejected = true; } inline bool none() const { return m_visit_code == NONE; } inline bool visited() const { return m_visit_code == VISITED; } inline bool started() const { return m_visit_code == STARTED; } inline bool finished() const { return m_visit_code == FINISHED; } inline bool rejected() const { return m_rejected; } inline bool finalized() const { return m_final; } inline void clear() { if (! m_rejected && ! m_final) { m_visit_code = NONE; } } inline void reset() { *this = visit_info(); } inline void finalize() { if (visited() || started() || finished() ) { m_final = true; } } #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION friend std::ostream& operator<<(std::ostream &os, visit_info const& v) { if (v.m_visit_code != 0) { os << " VIS: " << int(v.m_visit_code); } return os; } #endif }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP detail/overlay/convert_ring.hpp 0000644 00000006051 15125631657 0012714 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018-2020. // Modifications copyright (c) 2018-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP #include <boost/range/algorithm/reverse.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template<typename Tag> struct convert_ring { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for this geometry Tag.", Tag); }; template<> struct convert_ring<ring_tag> { template<typename Destination, typename Source> static inline void apply(Destination& destination, Source const& source, bool append, bool reverse) { if (! append) { geometry::convert(source, destination); if (reverse) { boost::reverse(destination); } } } }; template<> struct convert_ring<polygon_tag> { template<typename Destination, typename Source> static inline void apply(Destination& destination, Source const& source, bool append, bool reverse) { if (! append) { geometry::convert(source, exterior_ring(destination)); if (reverse) { boost::reverse(exterior_ring(destination)); } } else { // Avoid adding interior rings which are invalid // because of its number of points: std::size_t const min_num_points = core_detail::closure::minimum_ring_size < geometry::closure<Destination>::value >::value; if (geometry::num_points(source) >= min_num_points) { interior_rings(destination).resize( interior_rings(destination).size() + 1); geometry::convert(source, interior_rings(destination).back()); if (reverse) { boost::reverse(interior_rings(destination).back()); } } } } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP detail/overlay/overlay.hpp 0000644 00000036617 15125631657 0011711 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2013-2017 Adam Wulkiewicz, Lodz, Poland // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP #include <deque> #include <map> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp> #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/needs_self_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/traverse.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/reverse.hpp> #include <boost/geometry/algorithms/detail/overlay/add_rings.hpp> #include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp> #include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp> #include <boost/geometry/algorithms/detail/overlay/select_rings.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <boost/geometry/policies/robustness/segment_ratio_type.hpp> #include <boost/geometry/util/condition.hpp> #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE # include <boost/geometry/io/dsv/write.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { //! Default visitor for overlay, doing nothing struct overlay_null_visitor { void print(char const* ) {} template <typename Turns> void print(char const* , Turns const& , int) {} template <typename Turns> void print(char const* , Turns const& , int , int ) {} template <typename Turns> void visit_turns(int , Turns const& ) {} template <typename Clusters, typename Turns> void visit_clusters(Clusters const& , Turns const& ) {} template <typename Turns, typename Turn, typename Operation> void visit_traverse(Turns const& , Turn const& , Operation const& , char const*) {} template <typename Turns, typename Turn, typename Operation> void visit_traverse_reject(Turns const& , Turn const& , Operation const& , traverse_error_type ) {} template <typename Rings> void visit_generated_rings(Rings const& ) {} }; template < overlay_type OverlayType, typename TurnInfoMap, typename Turns, typename Clusters > inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; typedef typename turn_type::container_type container_type; static const operation_type target_operation = operation_from_overlay<OverlayType>::value; static const operation_type opposite_operation = target_operation == operation_union ? operation_intersection : operation_union; for (typename boost::range_iterator<Turns const>::type it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type const& turn = *it; bool cluster_checked = false; bool has_blocked = false; if (is_self_turn<OverlayType>(turn) && turn.discarded) { // Discarded self-turns don't count as traversed continue; } for (typename boost::range_iterator<container_type const>::type op_it = boost::begin(turn.operations); op_it != boost::end(turn.operations); ++op_it) { turn_operation_type const& op = *op_it; ring_identifier const ring_id = ring_id_by_seg_id(op.seg_id); if (! is_self_turn<OverlayType>(turn) && ( (BOOST_GEOMETRY_CONDITION(target_operation == operation_union) && op.enriched.count_left > 0) || (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection) && op.enriched.count_right <= 2))) { // Avoid including untraversed rings which have polygons on // their left side (union) or not two on their right side (int) // This can only be done for non-self-turns because of count // information turn_info_map[ring_id].has_blocked_turn = true; continue; } if (turn.any_blocked()) { turn_info_map[ring_id].has_blocked_turn = true; } if (turn_info_map[ring_id].has_traversed_turn || turn_info_map[ring_id].has_blocked_turn) { continue; } // Check information in colocated turns if (! cluster_checked && turn.is_clustered()) { check_colocation(has_blocked, turn.cluster_id, turns, clusters); cluster_checked = true; } // Block rings where any other turn is blocked, // and (with exceptions): i for union and u for intersection // Exceptions: don't block self-uu for intersection // don't block self-ii for union // don't block (for union) i/u if there is an self-ii too if (has_blocked || (op.operation == opposite_operation && ! turn.has_colocated_both && ! (turn.both(opposite_operation) && is_self_turn<OverlayType>(turn)))) { turn_info_map[ring_id].has_blocked_turn = true; } } } } template < typename GeometryOut, overlay_type OverlayType, bool ReverseOut, typename Geometry1, typename Geometry2, typename OutputIterator, typename Strategy > inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy) { typedef std::deque < typename geometry::ring_type<GeometryOut>::type > ring_container_type; typedef typename geometry::point_type<Geometry1>::type point_type1; typedef ring_properties < point_type1, typename Strategy::template area_strategy < point_type1 >::type::template result_type<point_type1>::type > properties; // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif // Union: return either of them // Intersection: return nothing // Difference: return first of them if (OverlayType == overlay_intersection || (OverlayType == overlay_difference && geometry::is_empty(geometry1))) { return out; } #if defined(_MSC_VER) #pragma warning(pop) #endif std::map<ring_identifier, ring_turn_info> empty; std::map<ring_identifier, properties> all_of_one_of_them; select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy); ring_container_type rings; assign_parents<OverlayType>(geometry1, geometry2, rings, all_of_one_of_them, strategy); return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out, strategy.template get_area_strategy<point_type1>()); } template < typename Geometry1, typename Geometry2, bool Reverse1, bool Reverse2, bool ReverseOut, typename GeometryOut, overlay_type OverlayType > struct overlay { template <typename RobustPolicy, typename OutputIterator, typename Strategy, typename Visitor> static inline OutputIterator apply( Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy, Visitor& visitor) { bool const is_empty1 = geometry::is_empty(geometry1); bool const is_empty2 = geometry::is_empty(geometry2); if (is_empty1 && is_empty2) { return out; } if (is_empty1 || is_empty2) { return return_if_one_input_is_empty < GeometryOut, OverlayType, ReverseOut >(geometry1, geometry2, out, strategy); } typedef typename geometry::point_type<GeometryOut>::type point_type; typedef detail::overlay::traversal_turn_info < point_type, typename segment_ratio_type<point_type, RobustPolicy>::type > turn_info; typedef std::deque<turn_info> turn_container_type; typedef std::deque < typename geometry::ring_type<GeometryOut>::type > ring_container_type; // Define the clusters, mapping cluster_id -> turns typedef std::map < signed_size_type, cluster_info > cluster_type; turn_container_type turns; #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "get turns" << std::endl; #endif detail::get_turns::no_interrupt_policy policy; geometry::get_turns < Reverse1, Reverse2, assign_policy_only_start_turns >(geometry1, geometry2, strategy, robust_policy, turns, policy); visitor.visit_turns(1, turns); #if ! defined(BOOST_GEOMETRY_NO_SELF_TURNS) if (! turns.empty() || OverlayType == overlay_dissolve) { // Calculate self turns if the output contains turns already, // and if necessary (e.g.: multi-geometry, polygon with interior rings) if (needs_self_turns<Geometry1>::apply(geometry1)) { self_get_turn_points::self_turns<Reverse1, assign_policy_only_start_turns>(geometry1, strategy, robust_policy, turns, policy, 0); } if (needs_self_turns<Geometry2>::apply(geometry2)) { self_get_turn_points::self_turns<Reverse2, assign_policy_only_start_turns>(geometry2, strategy, robust_policy, turns, policy, 1); } } #endif #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "enrich" << std::endl; #endif cluster_type clusters; std::map<ring_identifier, ring_turn_info> turn_info_per_ring; geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>( turns, clusters, geometry1, geometry2, robust_policy, strategy); visitor.visit_turns(2, turns); visitor.visit_clusters(clusters, turns); #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "traverse" << std::endl; #endif // Traverse through intersection/turn points and create rings of them. // Note that these rings are always in clockwise order, even in CCW polygons, // and are marked as "to be reversed" below ring_container_type rings; traverse<Reverse1, Reverse2, Geometry1, Geometry2, OverlayType>::apply ( geometry1, geometry2, strategy, robust_policy, turns, rings, turn_info_per_ring, clusters, visitor ); visitor.visit_turns(3, turns); get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters); typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type; typedef ring_properties < point_type, typename area_strategy_type::template result_type<point_type>::type > properties; // Select all rings which are NOT touched by any intersection point std::map<ring_identifier, properties> selected_ring_properties; select_rings<OverlayType>(geometry1, geometry2, turn_info_per_ring, selected_ring_properties, strategy); // Add rings created during traversal area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>(); { ring_identifier id(2, 0, -1); for (typename boost::range_iterator<ring_container_type>::type it = boost::begin(rings); it != boost::end(rings); ++it) { selected_ring_properties[id] = properties(*it, area_strategy); selected_ring_properties[id].reversed = ReverseOut; id.multi_index++; } } assign_parents<OverlayType>(geometry1, geometry2, rings, selected_ring_properties, strategy); // NOTE: There is no need to check result area for union because // as long as the polygons in the input are valid the resulting // polygons should be valid as well. // By default the area is checked (this is old behavior) however this // can be changed with #define. This may be important in non-cartesian CSes. // The result may be too big, so the area is negative. In this case either // it can be returned or an exception can be thrown. return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out, area_strategy, OverlayType == overlay_union ? #if defined(BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION) add_rings_throw_if_reversed #elif defined(BOOST_GEOMETRY_UNION_RETURN_INVALID) add_rings_add_unordered #else add_rings_ignore_unordered #endif : add_rings_ignore_unordered); } template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply( Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { overlay_null_visitor visitor; return apply(geometry1, geometry2, robust_policy, out, strategy, visitor); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP detail/overlay/get_turn_info_ll.hpp 0000644 00000067334 15125631657 0013561 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP #include <boost/throw_exception.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp> #include <boost/geometry/util/condition.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template<typename AssignPolicy> struct get_turn_info_linear_linear { static const bool handle_spikes = true; template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnInfo, typename UmbrellaStrategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo const& tp_model, UmbrellaStrategy const& umbrella_strategy, RobustPolicy const& robust_policy, OutputIterator out) { typedef intersection_info < UniqueSubRange1, UniqueSubRange2, typename TurnInfo::point_type, UmbrellaStrategy, RobustPolicy > inters_info; inters_info inters(range_p, range_q, umbrella_strategy, robust_policy); char const method = inters.d_info().how; // Copy, to copy possibly extended fields TurnInfo tp = tp_model; // Select method and apply switch(method) { case 'a' : // collinear, "at" case 'f' : // collinear, "from" case 's' : // starts from the middle get_turn_info_for_endpoint<true, true> ::apply(range_p, range_q, tp_model, inters, method_none, out, umbrella_strategy.get_point_in_point_strategy()); break; case 'd' : // disjoint: never do anything break; case 'm' : { if ( get_turn_info_for_endpoint<false, true> ::apply(range_p, range_q, tp_model, inters, method_touch_interior, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { typedef touch_interior < TurnInfo > policy; // If Q (1) arrives (1) if ( inters.d_info().arrival[1] == 1) { policy::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); } else { // Swap p/q policy::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), inters.get_swapped_sides(), umbrella_strategy); } if ( tp.operations[0].operation == operation_blocked ) { tp.operations[1].is_collinear = true; } if ( tp.operations[1].operation == operation_blocked ) { tp.operations[0].is_collinear = true; } replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); *out++ = tp; } } break; case 'i' : { crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info()); replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); *out++ = tp; } break; case 't' : { // Both touch (both arrive there) if ( get_turn_info_for_endpoint<false, true> ::apply(range_p, range_q, tp_model, inters, method_touch, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); // workarounds for touch<> not taking spikes into account starts here // those was discovered empirically // touch<> is not symmetrical! // P spikes and Q spikes may produce various operations! // TODO: this is not optimal solution - think about rewriting touch<> if ( tp.operations[0].operation == operation_blocked && tp.operations[1].operation == operation_blocked ) { // two touching spikes on the same line if ( inters.is_spike_p() && inters.is_spike_q() ) { tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_union; } else { tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = true; } } else if ( tp.operations[0].operation == operation_blocked ) { // a spike on P on the same line with Q1 if ( inters.is_spike_p() ) { if ( inters.sides().qk_wrt_p1() == 0 ) { tp.operations[0].is_collinear = true; } else { tp.operations[0].operation = operation_union; } } else { tp.operations[1].is_collinear = true; } } else if ( tp.operations[1].operation == operation_blocked ) { // a spike on Q on the same line with P1 if ( inters.is_spike_q() ) { if ( inters.sides().pk_wrt_q1() == 0 ) { tp.operations[1].is_collinear = true; } else { tp.operations[1].operation = operation_union; } } else { tp.operations[0].is_collinear = true; } } else if ( tp.operations[0].operation == operation_continue && tp.operations[1].operation == operation_continue ) { // P spike on the same line with Q2 (opposite) if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1() && inters.is_spike_p() ) { tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_union; } } else if ( tp.operations[0].operation == operation_none && tp.operations[1].operation == operation_none ) { // spike not handled by touch<> bool const is_p = inters.is_spike_p(); bool const is_q = inters.is_spike_q(); if ( is_p || is_q ) { tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_union; if ( inters.sides().pk_wrt_q2() == 0 ) { tp.operations[0].operation = operation_continue; // will be converted to i if ( is_p ) { tp.operations[0].is_collinear = true; } } if ( inters.sides().qk_wrt_p2() == 0 ) { tp.operations[1].operation = operation_continue; // will be converted to i if ( is_q ) { tp.operations[1].is_collinear = true; } } } } // workarounds for touch<> not taking spikes into account ends here replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_opposite_spikes<append_touches>(tp, inters, out) ) { *out++ = tp; } } } break; case 'e': { if ( get_turn_info_for_endpoint<true, true> ::apply(range_p, range_q, tp_model, inters, method_equal, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = true; if ( ! inters.d_info().opposite ) { // Both equal // or collinear-and-ending at intersection point equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); operation_type spike_op = ( tp.operations[0].operation != operation_continue || tp.operations[1].operation != operation_continue ) ? operation_union : operation_continue; // transform turn turn_transformer_ec transformer(method_touch); transformer(tp); // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, method_touch, spike_op, out) ) { *out++ = tp; // no spikes } } else { // TODO: ignore for spikes or generate something else than opposite? equal_opposite < TurnInfo, AssignPolicy >::apply(range_p, range_q, tp, out, inters); } } } break; case 'c' : { // Collinear if ( get_turn_info_for_endpoint<true, true> ::apply(range_p, range_q, tp_model, inters, method_collinear, out, umbrella_strategy.get_point_in_point_strategy()) ) { // do nothing } else { // NOTE: this is for spikes since those are set in the turn_transformer_ec tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = true; if ( ! inters.d_info().opposite ) { method_type method_replace = method_touch_interior; operation_type spike_op = operation_continue; if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); method_replace = method_touch; if ( tp.operations[0].operation != operation_continue || tp.operations[1].operation != operation_continue ) { spike_op = operation_union; } } else { collinear<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); //method_replace = method_touch_interior; //spike_op = operation_continue; } // transform turn turn_transformer_ec transformer(method_replace); transformer(tp); // conditionally handle spikes if ( ! BOOST_GEOMETRY_CONDITION(handle_spikes) || ! append_collinear_spikes(tp, inters, method_replace, spike_op, out) ) { // no spikes *out++ = tp; } } else { // If this always 'm' ? turn_transformer_ec transformer(method_touch_interior); // conditionally handle spikes if ( BOOST_GEOMETRY_CONDITION(handle_spikes) ) { append_opposite_spikes<append_collinear_opposite>(tp, inters, out); } // TODO: ignore for spikes? // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, // the same with is_q_valid collinear_opposite < TurnInfo, AssignPolicy >::apply(range_p, range_q, tp, out, inters, inters.sides(), transformer); } } } break; case '0' : { // degenerate points if ( BOOST_GEOMETRY_CONDITION(AssignPolicy::include_degenerate) ) { typedef typename UmbrellaStrategy::point_in_point_strategy_type equals_strategy_type; only_convert::apply(tp, inters.i_info()); // if any, only one of those should be true if ( range_p.is_first_segment() && equals::equals_point_point(range_p.at(0), tp.point, equals_strategy_type()) ) { tp.operations[0].position = position_front; } else if ( range_p.is_last_segment() && equals::equals_point_point(range_p.at(1), tp.point, equals_strategy_type()) ) { tp.operations[0].position = position_back; } else if ( range_q.is_first_segment() && equals::equals_point_point(range_q.at(0), tp.point, equals_strategy_type()) ) { tp.operations[1].position = position_front; } else if ( range_q.is_last_segment() && equals::equals_point_point(range_q.at(1), tp.point, equals_strategy_type()) ) { tp.operations[1].position = position_back; } *out++ = tp; } } break; default : { #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) std::cout << "TURN: Unknown method: " << method << std::endl; #endif #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) BOOST_THROW_EXCEPTION(turn_info_exception(method)); #endif } break; } return out; } template <typename TurnInfo, typename IntersectionInfo, typename OutIt> static inline bool append_collinear_spikes(TurnInfo & tp, IntersectionInfo const& inters_info, method_type method, operation_type spike_op, OutIt out) { // method == touch || touch_interior // both position == middle bool is_p_spike = tp.operations[0].operation == spike_op && inters_info.is_spike_p(); bool is_q_spike = tp.operations[1].operation == spike_op && inters_info.is_spike_q(); if ( is_p_spike && is_q_spike ) { if ( tp.method == method_equal && tp.operations[0].operation == operation_continue && tp.operations[1].operation == operation_continue ) { // treat both non-opposite collinear spikes as no-spikes return false; } tp.method = method; tp.operations[0].operation = operation_blocked; tp.operations[1].operation = operation_blocked; *out++ = tp; tp.operations[0].operation = operation_intersection; tp.operations[1].operation = operation_intersection; *out++ = tp; return true; } else if ( is_p_spike ) { tp.method = method; tp.operations[0].operation = operation_blocked; tp.operations[1].operation = operation_union; *out++ = tp; tp.operations[0].operation = operation_intersection; //tp.operations[1].operation = operation_union; *out++ = tp; return true; } else if ( is_q_spike ) { tp.method = method; tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_blocked; *out++ = tp; //tp.operations[0].operation = operation_union; tp.operations[1].operation = operation_intersection; *out++ = tp; return true; } return false; } enum append_version { append_touches, append_collinear_opposite }; template <append_version Version, typename TurnInfo, typename IntersectionInfo, typename OutIt> static inline bool append_opposite_spikes(TurnInfo & tp, IntersectionInfo const& inters, OutIt out) { static const bool is_version_touches = (Version == append_touches); bool is_p_spike = ( is_version_touches ? ( tp.operations[0].operation == operation_continue || tp.operations[0].operation == operation_intersection ) : true ) && inters.is_spike_p(); bool is_q_spike = ( is_version_touches ? ( tp.operations[1].operation == operation_continue || tp.operations[1].operation == operation_intersection ) : true ) && inters.is_spike_q(); bool res = false; if ( is_p_spike && ( BOOST_GEOMETRY_CONDITION(is_version_touches) || inters.d_info().arrival[0] == 1 ) ) { if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) { tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = false; tp.method = method_touch; } else // Version == append_collinear_opposite { tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = false; BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1); base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); } tp.operations[0].operation = operation_blocked; tp.operations[1].operation = operation_intersection; *out++ = tp; tp.operations[0].operation = operation_intersection; //tp.operations[1].operation = operation_intersection; *out++ = tp; res = true; } if ( is_q_spike && ( BOOST_GEOMETRY_CONDITION(is_version_touches) || inters.d_info().arrival[1] == 1 ) ) { if ( BOOST_GEOMETRY_CONDITION(is_version_touches) ) { tp.operations[0].is_collinear = false; tp.operations[1].is_collinear = true; tp.method = method_touch; } else // Version == append_collinear_opposite { tp.operations[0].is_collinear = false; tp.operations[1].is_collinear = true; BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0); base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0); } tp.operations[0].operation = operation_intersection; tp.operations[1].operation = operation_blocked; *out++ = tp; //tp.operations[0].operation = operation_intersection; tp.operations[1].operation = operation_intersection; *out++ = tp; res = true; } return res; } static inline void replace_method_and_operations_tm(method_type & method, operation_type & op0, operation_type & op1) { if ( op0 == operation_blocked && op1 == operation_blocked ) { // NOTE: probably only if methods are WRT IPs, not segments! method = (method == method_touch ? method_equal : method_collinear); op0 = operation_continue; op1 = operation_continue; } else { if ( op0 == operation_continue || op0 == operation_blocked ) { op0 = operation_intersection; } else if ( op0 == operation_intersection ) { op0 = operation_union; } if ( op1 == operation_continue || op1 == operation_blocked ) { op1 = operation_intersection; } else if ( op1 == operation_intersection ) { op1 = operation_union; } // spikes in 'm' if ( method == method_error ) { method = method_touch_interior; op0 = operation_union; op1 = operation_union; } } } class turn_transformer_ec { public: explicit turn_transformer_ec(method_type method_t_or_m) : m_method(method_t_or_m) {} template <typename Turn> void operator()(Turn & turn) const { operation_type & op0 = turn.operations[0].operation; operation_type & op1 = turn.operations[1].operation; BOOST_GEOMETRY_ASSERT(op0 != operation_blocked || op1 != operation_blocked ); if ( op0 == operation_blocked ) { op0 = operation_intersection; } else if ( op0 == operation_intersection ) { op0 = operation_union; } if ( op1 == operation_blocked ) { op1 = operation_intersection; } else if ( op1 == operation_intersection ) { op1 = operation_union; } if ( op0 == operation_intersection || op0 == operation_union || op1 == operation_intersection || op1 == operation_union ) { turn.method = m_method; } // TODO: is this correct? // it's equivalent to comparing to operation_blocked at the beginning of the function turn.operations[0].is_collinear = op0 != operation_intersection; turn.operations[1].is_collinear = op1 != operation_intersection; } private: method_type m_method; }; static inline void replace_operations_i(operation_type & op0, operation_type & op1) { if ( op0 == operation_intersection ) { op0 = operation_union; } if ( op1 == operation_intersection ) { op1 = operation_union; } } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP detail/overlay/get_ring.hpp 0000644 00000007526 15125631657 0012023 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template<typename Tag> struct get_ring {}; // A range of rings (multi-ring but that does not exist) // gets the "void" tag and is dispatched here. template<> struct get_ring<void> { template<typename Range> static inline typename boost::range_value<Range>::type const& apply(ring_identifier const& id, Range const& container) { return range::at(container, id.multi_index); } }; template<> struct get_ring<ring_tag> { template<typename Ring> static inline Ring const& apply(ring_identifier const& , Ring const& ring) { return ring; } }; template<> struct get_ring<box_tag> { template<typename Box> static inline Box const& apply(ring_identifier const& , Box const& box) { return box; } }; template<> struct get_ring<polygon_tag> { template<typename Polygon> static inline typename ring_return_type<Polygon const>::type const apply( ring_identifier const& id, Polygon const& polygon) { BOOST_GEOMETRY_ASSERT ( id.ring_index >= -1 && id.ring_index < int(boost::size(interior_rings(polygon))) ); return id.ring_index < 0 ? exterior_ring(polygon) : range::at(interior_rings(polygon), id.ring_index); } }; template<> struct get_ring<multi_polygon_tag> { template<typename MultiPolygon> static inline typename ring_type<MultiPolygon>::type const& apply( ring_identifier const& id, MultiPolygon const& multi_polygon) { BOOST_GEOMETRY_ASSERT ( id.multi_index >= 0 && id.multi_index < int(boost::size(multi_polygon)) ); return get_ring<polygon_tag>::apply(id, range::at(multi_polygon, id.multi_index)); } }; template <typename Geometry> inline std::size_t segment_count_on_ring(Geometry const& geometry, segment_identifier const& seg_id) { typedef typename geometry::tag<Geometry>::type tag; ring_identifier const rid(0, seg_id.multi_index, seg_id.ring_index); // A closed polygon, a triangle of 4 points, including starting point, // contains 3 segments. So handle as if closed and subtract one. return geometry::num_points(detail::overlay::get_ring<tag>::apply(rid, geometry), true) - 1; } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP detail/overlay/debug_turn_info.hpp 0000644 00000003703 15125631657 0013367 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/visit_info.hpp> namespace boost { namespace geometry { inline char method_char(detail::overlay::method_type const& method) { using namespace detail::overlay; switch(method) { case method_none : return '-'; case method_disjoint : return 'd'; case method_crosses : return 'i'; case method_touch : return 't'; case method_touch_interior : return 'm'; case method_collinear : return 'c'; case method_equal : return 'e'; case method_start : return 's'; case method_error : return '!'; default : return '?'; } } inline char operation_char(detail::overlay::operation_type const& operation) { using namespace detail::overlay; switch(operation) { case operation_none : return '-'; case operation_union : return 'u'; case operation_intersection : return 'i'; case operation_blocked : return 'x'; case operation_continue : return 'c'; case operation_opposite : return 'o'; default : return '?'; } } inline char visited_char(detail::overlay::visit_info const& v) { if (v.rejected()) return 'R'; if (v.started()) return 's'; if (v.visited()) return 'v'; if (v.none()) return '-'; if (v.finished()) return 'f'; return '?'; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP detail/overlay/get_intersection_points.hpp 0000644 00000010272 15125631657 0015156 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP #include <cstddef> #include <type_traits> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turns.hpp> #include <boost/geometry/policies/robustness/rescale_policy_tags.hpp> #include <boost/geometry/geometries/segment.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace get_intersection_points { template < typename Point1, typename Point2, typename TurnInfo > struct get_turn_without_info { template < typename UniqueSubRange1, typename UniqueSubRange2, typename Strategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo const& , Strategy const& strategy, RobustPolicy const& , OutputIterator out) { // Make sure this is only called with no rescaling BOOST_STATIC_ASSERT((std::is_same < no_rescale_policy_tag, typename rescale_policy_type<RobustPolicy>::type >::value)); typedef typename TurnInfo::point_type turn_point_type; typedef policies::relate::segments_intersection_points < segment_intersection_points<turn_point_type> > policy_type; typename policy_type::return_type const result = strategy.apply(range_p, range_q, policy_type()); for (std::size_t i = 0; i < result.count; i++) { TurnInfo tp; geometry::convert(result.intersections[i], tp.point); *out++ = tp; } return out; } }; }} // namespace detail::get_intersection_points #endif // DOXYGEN_NO_DETAIL template < typename Geometry1, typename Geometry2, typename RobustPolicy, typename Turns, typename Strategy > inline void get_intersection_points(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, Turns& turns, Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>(); typedef detail::get_intersection_points::get_turn_without_info < typename point_type<Geometry1>::type, typename point_type<Geometry2>::type, typename boost::range_value<Turns>::type > TurnPolicy; detail::get_turns::no_interrupt_policy interrupt_policy; std::conditional_t < reverse_dispatch<Geometry1, Geometry2>::type::value, dispatch::get_turns_reversed < typename tag<Geometry1>::type, typename tag<Geometry2>::type, Geometry1, Geometry2, false, false, TurnPolicy >, dispatch::get_turns < typename tag<Geometry1>::type, typename tag<Geometry2>::type, Geometry1, Geometry2, false, false, TurnPolicy > >::apply(0, geometry1, 1, geometry2, strategy, robust_policy, turns, interrupt_policy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP detail/overlay/handle_colocations.hpp 0000644 00000072235 15125631657 0014054 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_COLOCATIONS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_COLOCATIONS_HPP #include <cstddef> #include <algorithm> #include <map> #include <vector> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp> #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> #include <boost/geometry/util/condition.hpp> #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) # include <iostream> # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> # include <boost/geometry/io/wkt/wkt.hpp> # define BOOST_GEOMETRY_DEBUG_IDENTIFIER #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename SegmentRatio> struct segment_fraction { segment_identifier seg_id; SegmentRatio fraction; segment_fraction(segment_identifier const& id, SegmentRatio const& fr) : seg_id(id) , fraction(fr) {} segment_fraction() {} bool operator<(segment_fraction<SegmentRatio> const& other) const { return seg_id == other.seg_id ? fraction < other.fraction : seg_id < other.seg_id; } }; struct turn_operation_index { turn_operation_index(signed_size_type ti = -1, signed_size_type oi = -1) : turn_index(ti) , op_index(oi) {} signed_size_type turn_index; signed_size_type op_index; // only 0,1 }; template <typename Turns> struct less_by_fraction_and_type { inline less_by_fraction_and_type(Turns const& turns) : m_turns(turns) { } inline bool operator()(turn_operation_index const& left, turn_operation_index const& right) const { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; turn_type const& left_turn = m_turns[left.turn_index]; turn_type const& right_turn = m_turns[right.turn_index]; turn_operation_type const& left_op = left_turn.operations[left.op_index]; turn_operation_type const& right_op = right_turn.operations[right.op_index]; if (! (left_op.fraction == right_op.fraction)) { return left_op.fraction < right_op.fraction; } // Order xx first - used to discard any following colocated turn bool const left_both_xx = left_turn.both(operation_blocked); bool const right_both_xx = right_turn.both(operation_blocked); if (left_both_xx && ! right_both_xx) { return true; } if (! left_both_xx && right_both_xx) { return false; } bool const left_both_uu = left_turn.both(operation_union); bool const right_both_uu = right_turn.both(operation_union); if (left_both_uu && ! right_both_uu) { return true; } if (! left_both_uu && right_both_uu) { return false; } turn_operation_type const& left_other_op = left_turn.operations[1 - left.op_index]; turn_operation_type const& right_other_op = right_turn.operations[1 - right.op_index]; // Fraction is the same, now sort on ring id, first outer ring, // then interior rings return left_other_op.seg_id < right_other_op.seg_id; } private: Turns const& m_turns; }; template <typename Operation, typename ClusterPerSegment> inline signed_size_type get_cluster_id(Operation const& op, ClusterPerSegment const& cluster_per_segment) { typedef typename ClusterPerSegment::key_type segment_fraction_type; segment_fraction_type seg_frac(op.seg_id, op.fraction); typename ClusterPerSegment::const_iterator it = cluster_per_segment.find(seg_frac); if (it == cluster_per_segment.end()) { return -1; } return it->second; } template <typename Operation, typename ClusterPerSegment> inline void add_cluster_id(Operation const& op, ClusterPerSegment& cluster_per_segment, signed_size_type id) { typedef typename ClusterPerSegment::key_type segment_fraction_type; segment_fraction_type seg_frac(op.seg_id, op.fraction); cluster_per_segment[seg_frac] = id; } template <typename Turn, typename ClusterPerSegment> inline signed_size_type add_turn_to_cluster(Turn const& turn, ClusterPerSegment& cluster_per_segment, signed_size_type& cluster_id) { signed_size_type cid0 = get_cluster_id(turn.operations[0], cluster_per_segment); signed_size_type cid1 = get_cluster_id(turn.operations[1], cluster_per_segment); if (cid0 == -1 && cid1 == -1) { // Because of this, first cluster ID will be 1 ++cluster_id; add_cluster_id(turn.operations[0], cluster_per_segment, cluster_id); add_cluster_id(turn.operations[1], cluster_per_segment, cluster_id); return cluster_id; } else if (cid0 == -1 && cid1 != -1) { add_cluster_id(turn.operations[0], cluster_per_segment, cid1); return cid1; } else if (cid0 != -1 && cid1 == -1) { add_cluster_id(turn.operations[1], cluster_per_segment, cid0); return cid0; } else if (cid0 == cid1) { // Both already added to same cluster, no action return cid0; } // Both operations.seg_id/fraction were already part of any cluster, and // these clusters are not the same. Merge of two clusters is necessary #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) std::cout << " TODO: merge " << cid0 << " and " << cid1 << std::endl; #endif return cid0; } template < typename Turns, typename ClusterPerSegment, typename Operations, typename Geometry1, typename Geometry2 > inline void handle_colocation_cluster(Turns& turns, signed_size_type& cluster_id, ClusterPerSegment& cluster_per_segment, Operations const& operations, Geometry1 const& /*geometry1*/, Geometry2 const& /*geometry2*/) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; std::vector<turn_operation_index>::const_iterator vit = operations.begin(); turn_operation_index ref_toi = *vit; signed_size_type ref_id = -1; for (++vit; vit != operations.end(); ++vit) { turn_type& ref_turn = turns[ref_toi.turn_index]; turn_operation_type const& ref_op = ref_turn.operations[ref_toi.op_index]; turn_operation_index const& toi = *vit; turn_type& turn = turns[toi.turn_index]; turn_operation_type const& op = turn.operations[toi.op_index]; BOOST_GEOMETRY_ASSERT(ref_op.seg_id == op.seg_id); if (ref_op.fraction == op.fraction) { turn_operation_type const& other_op = turn.operations[1 - toi.op_index]; if (ref_id == -1) { ref_id = add_turn_to_cluster(ref_turn, cluster_per_segment, cluster_id); } BOOST_GEOMETRY_ASSERT(ref_id != -1); // ref_turn (both operations) are already added to cluster, // so also "op" is already added to cluster, // We only need to add other_op signed_size_type id = get_cluster_id(other_op, cluster_per_segment); if (id != -1 && id != ref_id) { } else if (id == -1) { // Add to same cluster add_cluster_id(other_op, cluster_per_segment, ref_id); id = ref_id; } } else { // Not on same fraction on this segment // assign for next ref_toi = toi; ref_id = -1; } } } template < typename Turns, typename Clusters, typename ClusterPerSegment > inline void assign_cluster_to_turns(Turns& turns, Clusters& clusters, ClusterPerSegment const& cluster_per_segment) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; typedef typename ClusterPerSegment::key_type segment_fraction_type; signed_size_type turn_index = 0; for (typename boost::range_iterator<Turns>::type it = turns.begin(); it != turns.end(); ++it, ++turn_index) { turn_type& turn = *it; if (turn.discarded) { // They were processed (to create proper map) but will not be added // This might leave a cluster with only 1 turn, which will be fixed // afterwards continue; } for (int i = 0; i < 2; i++) { turn_operation_type const& op = turn.operations[i]; segment_fraction_type seg_frac(op.seg_id, op.fraction); typename ClusterPerSegment::const_iterator cit = cluster_per_segment.find(seg_frac); if (cit != cluster_per_segment.end()) { #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) if (turn.is_clustered() && turn.cluster_id != cit->second) { std::cout << " CONFLICT " << std::endl; } #endif turn.cluster_id = cit->second; clusters[turn.cluster_id].turn_indices.insert(turn_index); } } } } template <typename Turns, typename Clusters> inline void remove_clusters(Turns& turns, Clusters& clusters) { typename Clusters::iterator it = clusters.begin(); while (it != clusters.end()) { // Hold iterator and increase. We can erase cit, this keeps the // iterator valid (cf The standard associative-container erase idiom) typename Clusters::iterator current_it = it; ++it; std::set<signed_size_type> const& turn_indices = current_it->second.turn_indices; if (turn_indices.size() == 1) { signed_size_type const turn_index = *turn_indices.begin(); turns[turn_index].cluster_id = -1; clusters.erase(current_it); } } } template <typename Turns, typename Clusters> inline void cleanup_clusters(Turns& turns, Clusters& clusters) { // Removes discarded turns from clusters for (typename Clusters::iterator mit = clusters.begin(); mit != clusters.end(); ++mit) { cluster_info& cinfo = mit->second; std::set<signed_size_type>& ids = cinfo.turn_indices; for (std::set<signed_size_type>::iterator sit = ids.begin(); sit != ids.end(); /* no increment */) { std::set<signed_size_type>::iterator current_it = sit; ++sit; signed_size_type const turn_index = *current_it; if (turns[turn_index].discarded) { ids.erase(current_it); } } } remove_clusters(turns, clusters); } template <typename Turn, typename IdSet> inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id) { turn.discarded = true; // Set cluster id to -1, but don't clear colocated flags turn.cluster_id = -1; // To remove it later from clusters ids.insert(id); } template <bool Reverse> inline bool is_interior(segment_identifier const& seg_id) { return Reverse ? seg_id.ring_index == -1 : seg_id.ring_index >= 0; } template <bool Reverse0, bool Reverse1> inline bool is_ie_turn(segment_identifier const& ext_seg_0, segment_identifier const& ext_seg_1, segment_identifier const& int_seg_0, segment_identifier const& other_seg_1) { if (ext_seg_0.source_index == ext_seg_1.source_index) { // External turn is a self-turn, dont discard internal turn for this return false; } // Compares two segment identifiers from two turns (external / one internal) // From first turn [0], both are from same polygon (multi_index), // one is exterior (-1), the other is interior (>= 0), // and the second turn [1] handles the same ring // For difference, where the rings are processed in reversal, all interior // rings become exterior and vice versa. But also the multi property changes: // rings originally from the same multi should now be considered as from // different multi polygons. // But this is not always the case, and at this point hard to figure out // (not yet implemented, TODO) bool const same_multi0 = ! Reverse0 && ext_seg_0.multi_index == int_seg_0.multi_index; bool const same_multi1 = ! Reverse1 && ext_seg_1.multi_index == other_seg_1.multi_index; boost::ignore_unused(same_multi1); return same_multi0 && same_multi1 && ! is_interior<Reverse0>(ext_seg_0) && is_interior<Reverse0>(int_seg_0) && ext_seg_1.ring_index == other_seg_1.ring_index; // The other way round is tested in another call } template < bool Reverse0, bool Reverse1, // Reverse interpretation interior/exterior typename Turns, typename Clusters > inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters) { typedef std::set<signed_size_type>::const_iterator set_iterator; typedef typename boost::range_value<Turns>::type turn_type; std::set<signed_size_type> ids_to_remove; for (typename Clusters::iterator cit = clusters.begin(); cit != clusters.end(); ++cit) { cluster_info& cinfo = cit->second; std::set<signed_size_type>& ids = cinfo.turn_indices; ids_to_remove.clear(); for (set_iterator it = ids.begin(); it != ids.end(); ++it) { turn_type& turn = turns[*it]; segment_identifier const& seg_0 = turn.operations[0].seg_id; segment_identifier const& seg_1 = turn.operations[1].seg_id; if (! (turn.both(operation_union) || turn.combination(operation_union, operation_blocked))) { // Not a uu/ux, so cannot be colocated with a iu turn continue; } for (set_iterator int_it = ids.begin(); int_it != ids.end(); ++int_it) { if (*it == *int_it) { continue; } // Turn with, possibly, an interior ring involved turn_type& int_turn = turns[*int_it]; segment_identifier const& int_seg_0 = int_turn.operations[0].seg_id; segment_identifier const& int_seg_1 = int_turn.operations[1].seg_id; if (is_ie_turn<Reverse0, Reverse1>(seg_0, seg_1, int_seg_0, int_seg_1)) { discard_ie_turn(int_turn, ids_to_remove, *int_it); } if (is_ie_turn<Reverse1, Reverse0>(seg_1, seg_0, int_seg_1, int_seg_0)) { discard_ie_turn(int_turn, ids_to_remove, *int_it); } } } // Erase from the ids (which cannot be done above) for (set_iterator sit = ids_to_remove.begin(); sit != ids_to_remove.end(); ++sit) { ids.erase(*sit); } } } template<typename Turns, typename Clusters> inline void discard_start_turns(Turns& turns, Clusters& clusters) { for (auto& nv : clusters) { cluster_info& cinfo = nv.second; auto& indices = cinfo.turn_indices; std::size_t start_count{0}; for (signed_size_type index : indices) { auto const& turn = turns[index]; if (turn.method == method_start) { start_count++; } } if (start_count == 0 && start_count == indices.size()) { // There are no start turns, or all turns in the cluster are start turns. continue; } // Discard the start turns and simultaneously erase them from the indices for (auto it = indices.begin(); it != indices.end();) { auto& turn = turns[*it]; if (turn.method == method_start) { turn.discarded = true; turn.cluster_id = -1; it = indices.erase(it); } else { ++it; } } } } template <typename Geometry0, typename Geometry1> inline segment_identifier get_preceding_segment_id(segment_identifier const& id, Geometry0 const& geometry0, Geometry1 const& geometry1) { segment_identifier result = id; if (result.segment_index == 0) { // Assign to segment_count before decrement result.segment_index = id.source_index == 0 ? segment_count_on_ring(geometry0, id) : segment_count_on_ring(geometry1, id); } result.segment_index--; return result; } template < overlay_type OverlayType, typename Turns, typename Clusters > inline void set_colocation(Turns& turns, Clusters const& clusters) { typedef std::set<signed_size_type>::const_iterator set_iterator; typedef typename boost::range_value<Turns>::type turn_type; for (typename Clusters::const_iterator cit = clusters.begin(); cit != clusters.end(); ++cit) { cluster_info const& cinfo = cit->second; std::set<signed_size_type> const& ids = cinfo.turn_indices; bool both_target = false; for (set_iterator it = ids.begin(); it != ids.end(); ++it) { turn_type const& turn = turns[*it]; if (turn.both(operation_from_overlay<OverlayType>::value)) { both_target = true; break; } } if (both_target) { for (set_iterator it = ids.begin(); it != ids.end(); ++it) { turn_type& turn = turns[*it]; turn.has_colocated_both = true; } } } } template < typename Turns, typename Clusters > inline void check_colocation(bool& has_blocked, signed_size_type cluster_id, Turns const& turns, Clusters const& clusters) { typedef typename boost::range_value<Turns>::type turn_type; has_blocked = false; typename Clusters::const_iterator mit = clusters.find(cluster_id); if (mit == clusters.end()) { return; } cluster_info const& cinfo = mit->second; for (std::set<signed_size_type>::const_iterator it = cinfo.turn_indices.begin(); it != cinfo.turn_indices.end(); ++it) { turn_type const& turn = turns[*it]; if (turn.any_blocked()) { has_blocked = true; } } } // Checks colocated turns and flags combinations of uu/other, possibly a // combination of a ring touching another geometry's interior ring which is // tangential to the exterior ring // This function can be extended to replace handle_tangencies: at each // colocation incoming and outgoing vectors should be inspected template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Turns, typename Clusters, typename Geometry1, typename Geometry2 > inline bool handle_colocations(Turns& turns, Clusters& clusters, Geometry1 const& geometry1, Geometry2 const& geometry2) { static const detail::overlay::operation_type target_operation = detail::overlay::operation_from_overlay<OverlayType>::value; typedef std::map < segment_identifier, std::vector<turn_operation_index> > map_type; // Create and fill map on segment-identifier Map is sorted on seg_id, // meaning it is sorted on ring_identifier too. This means that exterior // rings are handled first. If there is a colocation on the exterior ring, // that information can be used for the interior ring too map_type map; signed_size_type index = 0; for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it, ++index) { map[it->operations[0].seg_id].push_back(turn_operation_index(index, 0)); map[it->operations[1].seg_id].push_back(turn_operation_index(index, 1)); } // Check if there are multiple turns on one or more segments, // if not then nothing is to be done bool colocations = 0; for (typename map_type::const_iterator it = map.begin(); it != map.end(); ++it) { if (it->second.size() > 1u) { colocations = true; break; } } if (! colocations) { return false; } // Sort all vectors, per same segment less_by_fraction_and_type<Turns> less(turns); for (typename map_type::iterator it = map.begin(); it != map.end(); ++it) { std::sort(it->second.begin(), it->second.end(), less); } typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::segment_ratio_type segment_ratio_type; typedef std::map < segment_fraction<segment_ratio_type>, signed_size_type > cluster_per_segment_type; cluster_per_segment_type cluster_per_segment; // Assign to zero, because of pre-increment later the cluster_id // effectively starts with 1 // (and can later be negated to use uniquely with turn_index) signed_size_type cluster_id = 0; for (typename map_type::const_iterator it = map.begin(); it != map.end(); ++it) { if (it->second.size() > 1u) { handle_colocation_cluster(turns, cluster_id, cluster_per_segment, it->second, geometry1, geometry2); } } assign_cluster_to_turns(turns, clusters, cluster_per_segment); // Get colocated information here and not later, to keep information // on turns which are discarded afterwards set_colocation<OverlayType>(turns, clusters); discard_start_turns(turns, clusters); if (BOOST_GEOMETRY_CONDITION(target_operation == operation_intersection)) { discard_interior_exterior_turns < do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse1, do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2 >(turns, clusters); } #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS) std::cout << "*** Colocations " << map.size() << std::endl; for (typename map_type::const_iterator it = map.begin(); it != map.end(); ++it) { std::cout << it->first << std::endl; for (std::vector<turn_operation_index>::const_iterator vit = it->second.begin(); vit != it->second.end(); ++vit) { turn_operation_index const& toi = *vit; std::cout << geometry::wkt(turns[toi.turn_index].point) << std::boolalpha << " discarded=" << turns[toi.turn_index].discarded << " colocated(uu)=" << turns[toi.turn_index].colocated_uu << " colocated(ii)=" << turns[toi.turn_index].colocated_ii << " " << operation_char(turns[toi.turn_index].operations[0].operation) << " " << turns[toi.turn_index].operations[0].seg_id << " " << turns[toi.turn_index].operations[0].fraction << " // " << operation_char(turns[toi.turn_index].operations[1].operation) << " " << turns[toi.turn_index].operations[1].seg_id << " " << turns[toi.turn_index].operations[1].fraction << std::endl; } } #endif // DEBUG return true; } struct is_turn_index { is_turn_index(signed_size_type index) : m_index(index) {} template <typename Indexed> inline bool operator()(Indexed const& indexed) const { // Indexed is a indexed_turn_operation<Operation> return indexed.turn_index == m_index; } signed_size_type m_index; }; template < typename Sbs, typename Point, typename Turns, typename Geometry1, typename Geometry2 > inline bool fill_sbs(Sbs& sbs, Point& turn_point, cluster_info const& cinfo, Turns const& turns, Geometry1 const& geometry1, Geometry2 const& geometry2) { typedef typename boost::range_value<Turns>::type turn_type; std::set<signed_size_type> const& ids = cinfo.turn_indices; if (ids.empty()) { return false; } bool first = true; for (std::set<signed_size_type>::const_iterator sit = ids.begin(); sit != ids.end(); ++sit) { signed_size_type turn_index = *sit; turn_type const& turn = turns[turn_index]; if (first) { turn_point = turn.point; } for (int i = 0; i < 2; i++) { sbs.add(turn.operations[i], turn_index, i, geometry1, geometry2, first); first = false; } } return true; } template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Turns, typename Clusters, typename Geometry1, typename Geometry2, typename SideStrategy > inline void gather_cluster_properties(Clusters& clusters, Turns& turns, operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, SideStrategy const& strategy) { typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::point_type point_type; typedef typename turn_type::turn_operation_type turn_operation_type; // Define sorter, sorting counter-clockwise such that polygons are on the // right side typedef sort_by_side::side_sorter < Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int> > sbs_type; for (typename Clusters::iterator mit = clusters.begin(); mit != clusters.end(); ++mit) { cluster_info& cinfo = mit->second; sbs_type sbs(strategy); point_type turn_point; // should be all the same for all turns in cluster if (! fill_sbs(sbs, turn_point, cinfo, turns, geometry1, geometry2)) { continue; } sbs.apply(turn_point); sbs.find_open(); sbs.assign_zones(for_operation); cinfo.open_count = sbs.open_count(for_operation); bool const set_startable = OverlayType != overlay_dissolve; // Unset the startable flag for all 'closed' zones. This does not // apply for self-turns, because those counts are not from both // polygons for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { typename sbs_type::rp const& ranked = sbs.m_ranked_points[i]; turn_type& turn = turns[ranked.turn_index]; turn_operation_type& op = turn.operations[ranked.operation_index]; if (set_startable && for_operation == operation_union && cinfo.open_count == 0) { op.enriched.startable = false; } if (ranked.direction != sort_by_side::dir_to) { continue; } op.enriched.count_left = ranked.count_left; op.enriched.count_right = ranked.count_right; op.enriched.rank = ranked.rank; op.enriched.zone = ranked.zone; if (! set_startable) { continue; } if (BOOST_GEOMETRY_CONDITION(OverlayType != overlay_difference) && is_self_turn<OverlayType>(turn)) { // Difference needs the self-turns, TODO: investigate continue; } if ((for_operation == operation_union && ranked.count_left != 0) || (for_operation == operation_intersection && ranked.count_right != 2)) { op.enriched.startable = false; } } } } }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_COLOCATIONS_HPP detail/overlay/cluster_exits.hpp 0000644 00000017512 15125631657 0013116 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2020 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_EXITS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_EXITS_HPP #include <cstddef> #include <set> #include <vector> #include <boost/range/value_type.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/util/condition.hpp> #if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \ || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \ || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE) # include <string> # include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp> # include <boost/geometry/io/wkt/wkt.hpp> #endif namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // Structure to check relatively simple cluster cases template <overlay_type OverlayType, typename Turns, typename Sbs> struct cluster_exits { private : static const operation_type target_operation = operation_from_overlay<OverlayType>::value; typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; struct linked_turn_op_info { explicit linked_turn_op_info(signed_size_type ti = -1, int oi = -1, signed_size_type nti = -1) : turn_index(ti) , op_index(oi) , next_turn_index(nti) , rank_index(-1) {} signed_size_type turn_index; int op_index; signed_size_type next_turn_index; signed_size_type rank_index; }; typedef typename std::vector<linked_turn_op_info>::const_iterator const_it_type; typedef typename std::vector<linked_turn_op_info>::iterator it_type; typedef typename std::set<signed_size_type>::const_iterator sit_type; inline signed_size_type get_rank(Sbs const& sbs, linked_turn_op_info const& info) const { for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++) { typename Sbs::rp const& rp = sbs.m_ranked_points[i]; if (rp.turn_index == info.turn_index && rp.operation_index == info.op_index && rp.direction == sort_by_side::dir_to) { return rp.rank; } } return -1; } std::set<signed_size_type> const& m_ids; std::vector<linked_turn_op_info> possibilities; std::vector<linked_turn_op_info> blocked; bool m_valid; bool collect(Turns const& turns) { for (sit_type it = m_ids.begin(); it != m_ids.end(); ++it) { signed_size_type cluster_turn_index = *it; turn_type const& cluster_turn = turns[cluster_turn_index]; if (cluster_turn.discarded) { continue; } if (cluster_turn.both(target_operation)) { // Not (yet) supported, can be cluster of u/u turns return false; } for (int i = 0; i < 2; i++) { turn_operation_type const& op = cluster_turn.operations[i]; turn_operation_type const& other_op = cluster_turn.operations[1 - i]; signed_size_type const ni = op.enriched.get_next_turn_index(); if (op.operation == target_operation || op.operation == operation_continue) { if (ni == cluster_turn_index) { // Not (yet) supported, traveling to itself, can be // hole return false; } possibilities.push_back( linked_turn_op_info(cluster_turn_index, i, ni)); } else if (op.operation == operation_blocked && ! (ni == other_op.enriched.get_next_turn_index()) && m_ids.count(ni) == 0) { // Points to turn, not part of this cluster, // and that way is blocked. But if the other operation // points at the same turn, it is still fine. blocked.push_back( linked_turn_op_info(cluster_turn_index, i, ni)); } } } return true; } bool check_blocked(Sbs const& sbs) { if (blocked.empty()) { return true; } for (it_type it = possibilities.begin(); it != possibilities.end(); ++it) { linked_turn_op_info& info = *it; info.rank_index = get_rank(sbs, info); } for (it_type it = blocked.begin(); it != blocked.end(); ++it) { linked_turn_op_info& info = *it; info.rank_index = get_rank(sbs, info); } for (const_it_type it = possibilities.begin(); it != possibilities.end(); ++it) { linked_turn_op_info const& lti = *it; for (const_it_type bit = blocked.begin(); bit != blocked.end(); ++bit) { linked_turn_op_info const& blti = *bit; if (blti.next_turn_index == lti.next_turn_index && blti.rank_index == lti.rank_index) { return false; } } } return true; } public : cluster_exits(Turns const& turns, std::set<signed_size_type> const& ids, Sbs const& sbs) : m_ids(ids) , m_valid(collect(turns) && check_blocked(sbs)) { } inline bool apply(signed_size_type& turn_index, int& op_index, bool first_run = true) const { if (! m_valid) { return false; } // Traversal can either enter the cluster in the first turn, // or it can start halfway. // If there is one (and only one) possibility pointing outside // the cluster, take that one. linked_turn_op_info target; for (const_it_type it = possibilities.begin(); it != possibilities.end(); ++it) { linked_turn_op_info const& lti = *it; if (m_ids.count(lti.next_turn_index) == 0) { if (target.turn_index >= 0 && target.next_turn_index != lti.next_turn_index) { // Points to different target return false; } if (first_run && BOOST_GEOMETRY_CONDITION(OverlayType == overlay_buffer) && target.turn_index >= 0) { // Target already assigned, so there are more targets // or more ways to the same target return false; } target = lti; } } if (target.turn_index < 0) { return false; } turn_index = target.turn_index; op_index = target.op_index; return true; } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_EXITS_HPP detail/overlay/inconsistent_turns_exception.hpp 0000644 00000002023 15125631657 0016241 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2015, Oracle and/or its affiliates. // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INCONSISTENT_TURNS_EXCEPTION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INCONSISTENT_TURNS_EXCEPTION_HPP #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) #include <boost/geometry/core/exception.hpp> namespace boost { namespace geometry { class inconsistent_turns_exception : public geometry::exception { public: inline inconsistent_turns_exception() {} virtual ~inconsistent_turns_exception() throw() {} virtual char const* what() const throw() { return "Boost.Geometry Inconsistent Turns exception"; } }; }} // boost::geometry #endif // BOOST_GEOMETRY_OVERLAY_NO_THROW #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INCONSISTENT_TURNS_EXCEPTION_HPP detail/overlay/handle_self_turns.hpp 0000644 00000023477 15125631657 0013727 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2019-2020. // Modifications copyright (c) 2019-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp> #include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/covered_by.hpp> #include <boost/geometry/algorithms/within.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < typename Point, typename Geometry, typename Tag2 = typename geometry::tag<Geometry>::type > struct check_within_strategy { template <typename Strategy> static inline typename Strategy::template point_in_geometry_strategy<Point, Geometry>::type within(Strategy const& strategy) { return strategy.template get_point_in_geometry_strategy<Point, Geometry>(); } template <typename Strategy> static inline typename Strategy::template point_in_geometry_strategy<Point, Geometry>::type covered_by(Strategy const& strategy) { return strategy.template get_point_in_geometry_strategy<Point, Geometry>(); } }; template <typename Point, typename Geometry> struct check_within_strategy<Point, Geometry, box_tag> { template <typename Strategy> static inline typename Strategy::within_point_box_strategy_type within(Strategy const& ) { return typename Strategy::within_point_box_strategy_type(); } template <typename Strategy> static inline typename Strategy::covered_by_point_box_strategy_type covered_by(Strategy const&) { return typename Strategy::covered_by_point_box_strategy_type(); } }; template <overlay_type OverlayType> struct check_within { template < typename Turn, typename Geometry0, typename Geometry1, typename UmbrellaStrategy > static inline bool apply(Turn const& turn, Geometry0 const& geometry0, Geometry1 const& geometry1, UmbrellaStrategy const& strategy) { typedef typename Turn::point_type point_type; // Operations 0 and 1 have the same source index in self-turns return turn.operations[0].seg_id.source_index == 0 ? geometry::within(turn.point, geometry1, check_within_strategy<point_type, Geometry1>::within(strategy)) : geometry::within(turn.point, geometry0, check_within_strategy<point_type, Geometry0>::within(strategy)); } }; template <> struct check_within<overlay_difference> { template < typename Turn, typename Geometry0, typename Geometry1, typename UmbrellaStrategy > static inline bool apply(Turn const& turn, Geometry0 const& geometry0, Geometry1 const& geometry1, UmbrellaStrategy const& strategy) { typedef typename Turn::point_type point_type; // difference = intersection(a, reverse(b)) // therefore we should reverse the meaning of within for geometry1 return turn.operations[0].seg_id.source_index == 0 ? ! geometry::covered_by(turn.point, geometry1, check_within_strategy<point_type, Geometry1>::covered_by(strategy)) : geometry::within(turn.point, geometry0, check_within_strategy<point_type, Geometry0>::within(strategy)); } }; struct discard_turns { template < typename Turns, typename Clusters, typename Geometry0, typename Geometry1, typename Strategy > static inline void apply(Turns& , Clusters const& , Geometry0 const& , Geometry1 const& , Strategy const& ) {} }; template <overlay_type OverlayType, operation_type OperationType> struct discard_closed_turns : discard_turns {}; // It is only implemented for operation_union, not in buffer template <> struct discard_closed_turns<overlay_union, operation_union> { // Point in Geometry Strategy template < typename Turns, typename Clusters, typename Geometry0, typename Geometry1, typename Strategy > static inline void apply(Turns& turns, Clusters const& /*clusters*/, Geometry0 const& geometry0, Geometry1 const& geometry1, Strategy const& strategy) { typedef typename boost::range_value<Turns>::type turn_type; for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type& turn = *it; if (! turn.discarded && is_self_turn<overlay_union>(turn) && check_within<overlay_union>::apply(turn, geometry0, geometry1, strategy)) { // Turn is in the interior of other geometry turn.discarded = true; } } } }; template <overlay_type OverlayType> struct discard_self_intersection_turns { private : template <typename Turns, typename Clusters> static inline bool is_self_cluster(signed_size_type cluster_id, const Turns& turns, Clusters const& clusters) { typename Clusters::const_iterator cit = clusters.find(cluster_id); if (cit == clusters.end()) { return false; } cluster_info const& cinfo = cit->second; for (std::set<signed_size_type>::const_iterator it = cinfo.turn_indices.begin(); it != cinfo.turn_indices.end(); ++it) { if (! is_self_turn<OverlayType>(turns[*it])) { return false; } } return true; } template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1, typename Strategy> static inline void discard_clusters(Turns& turns, Clusters const& clusters, Geometry0 const& geometry0, Geometry1 const& geometry1, Strategy const& strategy) { for (typename Clusters::const_iterator cit = clusters.begin(); cit != clusters.end(); ++cit) { signed_size_type const cluster_id = cit->first; // If there are only self-turns in the cluster, the cluster should // be located within the other geometry, for intersection if (! cit->second.turn_indices.empty() && is_self_cluster(cluster_id, turns, clusters)) { cluster_info const& cinfo = cit->second; signed_size_type const index = *cinfo.turn_indices.begin(); if (! check_within<OverlayType>::apply(turns[index], geometry0, geometry1, strategy)) { // Discard all turns in cluster for (std::set<signed_size_type>::const_iterator sit = cinfo.turn_indices.begin(); sit != cinfo.turn_indices.end(); ++sit) { turns[*sit].discarded = true; } } } } } public : template <typename Turns, typename Clusters, typename Geometry0, typename Geometry1, typename Strategy> static inline void apply(Turns& turns, Clusters const& clusters, Geometry0 const& geometry0, Geometry1 const& geometry1, Strategy const& strategy) { discard_clusters(turns, clusters, geometry0, geometry1, strategy); typedef typename boost::range_value<Turns>::type turn_type; for (typename boost::range_iterator<Turns>::type it = boost::begin(turns); it != boost::end(turns); ++it) { turn_type& turn = *it; // It is a ii self-turn // Check if it is within the other geometry if (! turn.discarded && is_self_turn<overlay_intersection>(turn) && ! check_within<OverlayType>::apply(turn, geometry0, geometry1, strategy)) { // It is not within another geometry, set it as non startable. // It still might be traveled (#case_recursive_boxes_70) turn.operations[0].enriched.startable = false; turn.operations[1].enriched.startable = false; } } } }; template <overlay_type OverlayType, operation_type OperationType> struct discard_open_turns : discard_turns {}; // Handler for intersection template <> struct discard_open_turns<overlay_intersection, operation_intersection> : discard_self_intersection_turns<overlay_intersection> {}; // Handler for difference, with different meaning of 'within' template <> struct discard_open_turns<overlay_difference, operation_intersection> : discard_self_intersection_turns<overlay_difference> {}; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP detail/overlay/intersection_box_box.hpp 0000644 00000005077 15125631657 0014452 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015. // Modifications copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace intersection { template <std::size_t Dimension, std::size_t DimensionCount> struct intersection_box_box { template < typename Box1, typename Box2, typename RobustPolicy, typename BoxOut, typename Strategy > static inline bool apply(Box1 const& box1, Box2 const& box2, RobustPolicy const& robust_policy, BoxOut& box_out, Strategy const& strategy) { typedef typename coordinate_type<BoxOut>::type ct; ct max1 = get<max_corner, Dimension>(box1); ct min2 = get<min_corner, Dimension>(box2); if (max1 < min2) { return false; } ct max2 = get<max_corner, Dimension>(box2); ct min1 = get<min_corner, Dimension>(box1); if (max2 < min1) { return false; } // Set dimensions of output coordinate set<min_corner, Dimension>(box_out, min1 < min2 ? min2 : min1); set<max_corner, Dimension>(box_out, max1 > max2 ? max2 : max1); return intersection_box_box<Dimension + 1, DimensionCount> ::apply(box1, box2, robust_policy, box_out, strategy); } }; template <std::size_t DimensionCount> struct intersection_box_box<DimensionCount, DimensionCount> { template < typename Box1, typename Box2, typename RobustPolicy, typename BoxOut, typename Strategy > static inline bool apply(Box1 const&, Box2 const&, RobustPolicy const&, BoxOut&, Strategy const&) { return true; } }; }} // namespace detail::intersection #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_BOX_BOX_HPP detail/overlay/get_relative_order.hpp 0000644 00000006274 15125631657 0014071 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017. // Modifications copyright (c) 2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP #include <boost/geometry/strategies/intersection_strategies.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { /*! \brief Get relative order \details Can indicate which of two segments R and S, both crossing a common segment P, comes first. If the two segments cross P very close (e.g. in a spike), the distance between the intersection points can be zero, but we still need to know which comes first. Therefore, it is useful that using sides we are able to discover this. */ struct get_relative_order { template <typename Point, typename SideStrategy> static inline int value_via_product(Point const& ti, Point const& tj, Point const& ui, Point const& uj, int factor, SideStrategy const& strategy) { int const side_ti_u = strategy.apply(ti, tj, ui); int const side_tj_u = strategy.apply(ti, tj, uj); #ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER std::cout << (factor == 1 ? " r//s " : " s//r ") << side_ti_u << " / " << side_tj_u; #endif return side_ti_u * side_tj_u >= 0 ? factor * (side_ti_u != 0 ? side_ti_u : side_tj_u) : 0; } template <typename Point1, typename SideStrategy> static inline int apply( Point1 const& pi, Point1 const& pj, Point1 const& ri, Point1 const& rj, Point1 const& si, Point1 const& sj, SideStrategy const& strategy) { int const side_ri_p = strategy.apply(pi, pj, ri); int const side_si_p = strategy.apply(pi, pj, si); #ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER int const side_rj_p = strategy::apply(pi, pj, rj); int const side_sj_p = strategy::apply(pi, pj, sj); std::cout << "r//p: " << side_ri_p << " / " << side_rj_p; std::cout << " s//p: " << side_si_p << " / " << side_sj_p; #endif int value = value_via_product(si, sj, ri, rj, 1, strategy); if (value == 0) { value = value_via_product(ri, rj, si, sj, -1, strategy); } int const order = side_ri_p * side_ri_p * side_si_p * value; #ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER std::cout << " o: " << order << std::endl << std::endl; #endif return order; } }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP detail/overlay/get_turn_info_for_endpoint.hpp 0000644 00000061317 15125631657 0015633 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013, 2014, 2017, 2018. // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP #include <boost/core/ignore_unused.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // SEGMENT_INTERSECTION RESULT // C H0 H1 A0 A1 O IP1 IP2 // D0 and D1 == 0 // |--------> 2 0 0 0 0 F i/i x/x // |--------> // // |--------> 2 0 0 0 0 T i/x x/i // <--------| // // |-----> 1 0 0 0 0 T x/x // <-----| // // |---------> 2 0 0 0 1 T i/x x/i // <----| // // |---------> 2 0 0 0 0 F i/i x/x // |----> // // |---------> 2 0 0 -1 1 F i/i u/x // |----> // // |---------> 2 0 0 -1 0 T i/x u/i // <----| // |-------> 2 0 0 1 -1 F and i/i x/u // |-------> 2 0 0 -1 1 F symmetric i/i u/x // |-------> // // |-------> 2 0 0 -1 -1 T i/u u/i // <-------| // // |-------> 2 0 0 1 1 T i/x x/i // <-------| // // |--------> 2 0 0 -1 1 F i/i u/x // |----> // // |--------> 2 0 0 -1 1 T i/x u/i // <----| // |-----> 1 -1 -1 -1 -1 T u/u // <-----| // // |-----> 1 -1 0 -1 0 F and u/x // |-----> 1 0 -1 0 -1 F symmetric x/u // |-----> // D0 or D1 != 0 // ^ // | // + 1 -1 1 -1 1 F and u/x (P is vertical) // |--------> 1 1 -1 1 -1 F symmetric x/u (P is horizontal) // ^ // | // + // // + // | // v // |--------> 1 1 1 1 1 F x/x (P is vertical) // // ^ // | // + // |--------> 1 -1 -1 -1 -1 F u/u (P is vertical) // // ^ // | // + // |--------> 1 0 -1 0 -1 F u/u (P is vertical) // // + // | // v // |--------> 1 0 1 0 1 F u/x (P is vertical) // class linear_intersections { public: template <typename Point1, typename Point2, typename IntersectionResult, typename EqPPStrategy> linear_intersections(Point1 const& pi, Point2 const& qi, IntersectionResult const& result, bool is_p_last, bool is_q_last, EqPPStrategy const& strategy) { int arrival_a = result.direction.arrival[0]; int arrival_b = result.direction.arrival[1]; bool same_dirs = result.direction.dir_a == 0 && result.direction.dir_b == 0; if ( same_dirs ) { if ( result.intersection_points.count == 2 ) { if ( ! result.direction.opposite ) { ips[0].p_operation = operation_intersection; ips[0].q_operation = operation_intersection; ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); ips[0].is_pi = equals::equals_point_point( pi, result.intersection_points.intersections[0], strategy); ips[0].is_qi = equals::equals_point_point( qi, result.intersection_points.intersections[0], strategy); ips[1].is_pj = arrival_a != -1; ips[1].is_qj = arrival_b != -1; } else { ips[0].p_operation = operation_intersection; ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); ips[1].q_operation = operation_intersection; ips[0].is_pi = arrival_b != 1; ips[0].is_qj = arrival_b != -1; ips[1].is_pj = arrival_a != -1; ips[1].is_qi = arrival_a != 1; } } else { BOOST_GEOMETRY_ASSERT(result.intersection_points.count == 1); ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); ips[0].is_pi = arrival_a == -1; ips[0].is_qi = arrival_b == -1; ips[0].is_pj = arrival_a == 0; ips[0].is_qj = arrival_b == 0; } } else { ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last); ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last); ips[0].is_pi = arrival_a == -1; ips[0].is_qi = arrival_b == -1; ips[0].is_pj = arrival_a == 1; ips[0].is_qj = arrival_b == 1; } } struct ip_info { inline ip_info() : p_operation(operation_none), q_operation(operation_none) , is_pi(false), is_pj(false), is_qi(false), is_qj(false) {} operation_type p_operation, q_operation; bool is_pi, is_pj, is_qi, is_qj; }; template <std::size_t I> ip_info const& get() const { BOOST_STATIC_ASSERT(I < 2); return ips[I]; } private: // only if collinear (same_dirs) static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last) { if ( arrival == 1 ) return operation_blocked; else if ( arrival == -1 ) return operation_union; else return is_last ? operation_blocked : operation_union; //return operation_blocked; } // only if not collinear (!same_dirs) static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last) { if ( arrival == 1 ) //return operation_blocked; return is_last ? operation_blocked : operation_union; else return operation_union; } ip_info ips[2]; }; template <bool EnableFirst, bool EnableLast> struct get_turn_info_for_endpoint { typedef std::pair<operation_type, operation_type> operations_pair; BOOST_STATIC_ASSERT(EnableFirst || EnableLast); template<typename UniqueSubRange1, typename UniqueSubRange2, typename TurnInfo, typename IntersectionInfo, typename OutputIterator, typename EqPPStrategy > static inline bool apply(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo const& tp_model, IntersectionInfo const& inters, method_type /*method*/, OutputIterator out, EqPPStrategy const& strategy) { std::size_t ip_count = inters.i_info().count; // no intersection points if (ip_count == 0) { return false; } if (! range_p.is_first_segment() && ! range_q.is_first_segment() && ! range_p.is_last_segment() && ! range_q.is_last_segment()) { // Not an end-point from segment p or q return false; } linear_intersections intersections(range_p.at(0), range_q.at(0), inters.result(), range_p.is_last_segment(), range_q.is_last_segment(), strategy); bool append0_last = analyse_segment_and_assign_ip(range_p, range_q, intersections.template get<0>(), tp_model, inters, 0, out); // NOTE: opposite && ip_count == 1 may be true! bool opposite = inters.d_info().opposite; // don't ignore only for collinear opposite bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite ); if ( intersections.template get<1>().p_operation == operation_none ) return result_ignore_ip0; bool append1_last = analyse_segment_and_assign_ip(range_p, range_q, intersections.template get<1>(), tp_model, inters, 1, out); // don't ignore only for collinear opposite bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/; return result_ignore_ip0 || result_ignore_ip1; } template <typename UniqueSubRange1, typename UniqueSubRange2, typename TurnInfo, typename IntersectionInfo, typename OutputIterator> static inline bool analyse_segment_and_assign_ip(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, linear_intersections::ip_info const& ip_info, TurnInfo const& tp_model, IntersectionInfo const& inters, unsigned int ip_index, OutputIterator out) { // TODO - calculate first/last only if needed bool is_p_first_ip = range_p.is_first_segment() && ip_info.is_pi; bool is_p_last_ip = range_p.is_last_segment() && ip_info.is_pj; bool is_q_first_ip = range_q.is_first_segment() && ip_info.is_qi; bool is_q_last_ip = range_q.is_last_segment() && ip_info.is_qj; bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip); bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip); operation_type p_operation = ip_info.p_operation; operation_type q_operation = ip_info.q_operation; if ( append_first || append_last ) { bool handled = handle_internal<0>(range_p, range_q, is_p_first_ip, is_p_last_ip, is_q_first_ip, is_q_last_ip, ip_info.is_qi, ip_info.is_qj, tp_model, inters, ip_index, p_operation, q_operation); if ( !handled ) { // Reverse p/q handle_internal<1>(range_q, range_p, is_q_first_ip, is_q_last_ip, is_p_first_ip, is_p_last_ip, ip_info.is_pi, ip_info.is_pj, tp_model, inters, ip_index, q_operation, p_operation); } if ( p_operation != operation_none ) { method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj, ip_info.is_qi, ip_info.is_qj); turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip); turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip); // handle spikes // P is spike and should be handled if (ip_info.is_pj // this check is redundant (also in is_spike_p) but faster && inters.i_info().count == 2 && inters.is_spike_p() ) { assign(inters.result(), ip_index, method, operation_blocked, q_operation, p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); assign(inters.result(), ip_index, method, operation_intersection, q_operation, p_pos, q_pos, is_p_first_ip, is_q_first_ip, true, false, tp_model, out); } // Q is spike and should be handled else if (ip_info.is_qj // this check is redundant (also in is_spike_q) but faster && inters.i_info().count == 2 && inters.is_spike_q() ) { assign(inters.result(), ip_index, method, p_operation, operation_blocked, p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); assign(inters.result(), ip_index, method, p_operation, operation_intersection, p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, true, tp_model, out); } // no spikes else { assign(inters.result(), ip_index, method, p_operation, q_operation, p_pos, q_pos, is_p_first_ip, is_q_first_ip, false, false, tp_model, out); } } } return append_last; } // TODO: IT'S ALSO PROBABLE THAT ALL THIS FUNCTION COULD BE INTEGRATED WITH handle_segment // however now it's lazily calculated and then it would be always calculated template<std::size_t G1Index, typename UniqueRange1, typename UniqueRange2, typename TurnInfo, typename IntersectionInfo > static inline bool handle_internal(UniqueRange1 const& range1, UniqueRange2 const& range2, bool first1, bool last1, bool first2, bool last2, bool ip_i2, bool ip_j2, TurnInfo const& tp_model, IntersectionInfo const& inters, unsigned int ip_index, operation_type & op1, operation_type & op2) { boost::ignore_unused(ip_index, tp_model); typename IntersectionInfo::side_strategy_type const& sides = inters.get_side_strategy(); if ( !first2 && !last2 ) { if ( first1 ) { #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR // may this give false positives for INTs? typename IntersectionResult::point_type const& inters_pt = inters.i_info().intersections[ip_index]; BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); #endif if ( ip_i2 ) { // don't output this IP - for the first point of other geometry segment op1 = operation_none; op2 = operation_none; return true; } else if ( ip_j2 ) { int const side_pj_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(1)); int const side_pj_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(1)); int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2)); operations_pair operations = operations_of_equal(side_pj_q2, side_pj_q1, side_qk_q1); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? if ( operations_both(operations, operation_continue) ) { if ( op1 != operation_union || op2 != operation_union || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) { // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! bool opposite = inters.d_info().opposite; op1 = operation_intersection; op2 = opposite ? operation_union : operation_intersection; } } else { BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union)); //op1 = operation_union; //op2 = operation_union; } return true; } // else do nothing - shouldn't be handled this way } else if ( last1 ) { #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR // may this give false positives for INTs? typename IntersectionResult::point_type const& inters_pt = inters.i_info().intersections[ip_index]; BOOST_GEOMETRY_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); BOOST_GEOMETRY_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); #endif if ( ip_i2 ) { // don't output this IP - for the first point of other geometry segment op1 = operation_none; op2 = operation_none; return true; } else if ( ip_j2 ) { int const side_pi_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(0)); int const side_pi_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(0)); int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2)); operations_pair operations = operations_of_equal(side_pi_q2, side_pi_q1, side_qk_q1); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? if ( operations_both(operations, operation_continue) ) { if ( op1 != operation_blocked || op2 != operation_union || ! ( G1Index == 0 ? inters.is_spike_q() : inters.is_spike_p() ) ) { // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! bool second_going_out = inters.i_info().count > 1; op1 = operation_blocked; op2 = second_going_out ? operation_union : operation_intersection; } } else { BOOST_GEOMETRY_ASSERT(operations_combination(operations, operation_intersection, operation_union)); //op1 = operation_blocked; //op2 = operation_union; } return true; } // else do nothing - shouldn't be handled this way } // else do nothing - shouldn't be handled this way } return false; } static inline method_type endpoint_ip_method(bool ip_pi, bool ip_pj, bool ip_qi, bool ip_qj) { if ( (ip_pi || ip_pj) && (ip_qi || ip_qj) ) return method_touch; else return method_touch_interior; } static inline turn_position ip_position(bool is_ip_first_i, bool is_ip_last_j) { return is_ip_first_i ? position_front : ( is_ip_last_j ? position_back : position_middle ); } template <typename IntersectionResult, typename TurnInfo, typename OutputIterator> static inline void assign(IntersectionResult const& result, unsigned int ip_index, method_type method, operation_type op0, operation_type op1, turn_position pos0, turn_position pos1, bool is_p_first_ip, bool is_q_first_ip, bool is_p_spike, bool is_q_spike, TurnInfo const& tp_model, OutputIterator out) { TurnInfo tp = tp_model; //geometry::convert(ip, tp.point); //tp.method = method; base_turn_handler::assign_point(tp, method, result.intersection_points, ip_index); tp.operations[0].operation = op0; tp.operations[1].operation = op1; tp.operations[0].position = pos0; tp.operations[1].position = pos1; if ( result.intersection_points.count > 1 ) { // NOTE: is_collinear is NOT set for the first endpoint // for which there is no preceding segment //BOOST_GEOMETRY_ASSERT( result.direction.dir_a == 0 && result.direction.dir_b == 0 ); if ( ! is_p_first_ip ) { tp.operations[0].is_collinear = op0 != operation_intersection || is_p_spike; } if ( ! is_q_first_ip ) { tp.operations[1].is_collinear = op1 != operation_intersection || is_q_spike; } } else //if ( result.intersection_points.count == 1 ) { if ( op0 == operation_blocked && op1 == operation_intersection ) { tp.operations[0].is_collinear = true; } else if ( op0 == operation_intersection && op1 == operation_blocked ) { tp.operations[1].is_collinear = true; } } *out++ = tp; } static inline operations_pair operations_of_equal(int side_px_q2, int side_px_q1, int side_qk_q1) { // If px (pi or pj) is collinear with qj-qk (q2), they continue collinearly. // This can be on either side of q1, or collinear // The second condition checks if they do not continue // oppositely if (side_px_q2 == 0 && side_px_q1 == side_qk_q1) { return std::make_pair(operation_continue, operation_continue); } // If they turn to same side (not opposite sides) if ( ! base_turn_handler::opposite(side_px_q1, side_qk_q1) ) { // If px is left of q2 or collinear: p: union, q: intersection if (side_px_q2 != -1 ) { return std::make_pair(operation_union, operation_intersection); } else { return std::make_pair(operation_intersection, operation_union); } } else { // They turn opposite sides. If p turns left (or collinear), // p: union, q: intersection if (side_px_q1 != -1 ) { return std::make_pair(operation_union, operation_intersection); } else { return std::make_pair(operation_intersection, operation_union); } } } static inline bool operations_both(operations_pair const& operations, operation_type const op) { return operations.first == op && operations.second == op; } static inline bool operations_combination(operations_pair const& operations, operation_type const op1, operation_type const op2) { return ( operations.first == op1 && operations.second == op2 ) || ( operations.first == op2 && operations.second == op1 ); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP detail/overlay/cluster_info.hpp 0000644 00000001762 15125631657 0012715 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2016 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_INFO_HPP #include <set> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { struct cluster_info { std::set<signed_size_type> turn_indices; //! Number of open spaces (e.g. 2 for touch) std::size_t open_count; inline cluster_info() : open_count(0) {} }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLUSTER_INFO_HPP detail/overlay/stream_info.hpp 0000644 00000004517 15125631657 0012530 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2018. // Modifications copyright (c) 2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP #include <string> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { static inline std::string dir(int d) { return d == 0 ? "-" : (d == 1 ? "L" : d == -1 ? "R" : "#"); } static inline std::string how_str(int h) { return h == 0 ? "-" : (h == 1 ? "A" : "D"); } template <typename P, typename SR, typename O, typename C> std::ostream& operator<<(std::ostream &os, turn_info<P, SR, O, C> const& info) { os << "\t" << " src " << info.seg_id.source_index << " seg " << info.seg_id.segment_index << " (// " << info.other_id.source_index << "." << info.other_id.segment_index << ")" << " how " << info.how << "[" << how_str(info.arrival) << " " << dir(info.direction) << (info.opposite ? " o" : "") << "]" << " sd " << dir(info.sides.template get<0,0>()) << dir(info.sides.template get<0,1>()) << dir(info.sides.template get<1,0>()) << dir(info.sides.template get<1,1>()) << " nxt seg " << info.travels_to_vertex_index << " , ip " << info.travels_to_ip_index << " , or " << info.next_ip_index << " frac " << info.fraction << info.visit_state; if (info.flagged) { os << " FLAGGED"; } return os; } }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP detail/overlay/ring_properties.hpp 0000644 00000004127 15125631657 0013432 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017. // Modifications copyright (c) 2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP #include <boost/geometry/algorithms/area.hpp> #include <boost/geometry/algorithms/within.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Point, typename AreaType> struct ring_properties { typedef Point point_type; typedef AreaType area_type; bool valid; // Filled by "select_rings" Point point; area_type area; // Filled by "update_ring_selection" bool reversed; // Filled/used by "assign_rings" bool discarded; ring_identifier parent; area_type parent_area; std::vector<ring_identifier> children; inline ring_properties() : valid(false) , area(area_type()) , reversed(false) , discarded(false) , parent_area(-1) {} template <typename RingOrBox, typename AreaStrategy> inline ring_properties(RingOrBox const& ring_or_box, AreaStrategy const& strategy) : reversed(false) , discarded(false) , parent_area(-1) { this->area = geometry::area(ring_or_box, strategy); valid = geometry::point_on_border(this->point, ring_or_box); } inline area_type get_area() const { return reversed ? -area : area; } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP detail/overlay/segment_identifier.hpp 0000644 00000006743 15125631657 0014071 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP #if defined(BOOST_GEOMETRY_DEBUG_OVERLAY) # define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif #if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER) #include <iostream> #endif #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/algorithms/detail/ring_identifier.hpp> namespace boost { namespace geometry { // Internal struct to uniquely identify a segment // on a linestring,ring // or polygon (needs ring_index) // or multi-geometry (needs multi_index) struct segment_identifier { inline segment_identifier() : source_index(-1) , multi_index(-1) , ring_index(-1) , segment_index(-1) , piece_index(-1) {} inline segment_identifier(signed_size_type src, signed_size_type mul, signed_size_type rin, signed_size_type seg) : source_index(src) , multi_index(mul) , ring_index(rin) , segment_index(seg) , piece_index(-1) {} inline bool operator<(segment_identifier const& other) const { return source_index != other.source_index ? source_index < other.source_index : multi_index !=other.multi_index ? multi_index < other.multi_index : ring_index != other.ring_index ? ring_index < other.ring_index : piece_index != other.piece_index ? piece_index < other.piece_index : segment_index < other.segment_index ; } inline bool operator==(segment_identifier const& other) const { return source_index == other.source_index && segment_index == other.segment_index && ring_index == other.ring_index && piece_index == other.piece_index && multi_index == other.multi_index ; } #if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER) friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id) { os << "s:" << seg_id.source_index << ", v:" << seg_id.segment_index // v:vertex because s is used for source ; if (seg_id.ring_index >= 0) os << ", r:" << seg_id.ring_index; if (seg_id.multi_index >= 0) os << ", m:" << seg_id.multi_index; if (seg_id.piece_index >= 0) os << ", p:" << seg_id.piece_index; return os; } #endif signed_size_type source_index; signed_size_type multi_index; signed_size_type ring_index; signed_size_type segment_index; // For buffer - todo: move this to buffer-only signed_size_type piece_index; }; #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // Create a ring identifier from a segment identifier inline ring_identifier ring_id_by_seg_id(segment_identifier const& seg_id) { return ring_identifier(seg_id.source_index, seg_id.multi_index, seg_id.ring_index); } }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP detail/overlay/traversal_info.hpp 0000644 00000002675 15125631657 0013243 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp> #include <boost/geometry/algorithms/detail/overlay/visit_info.hpp> #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template <typename Point, typename SegmentRatio> struct traversal_turn_operation : public turn_operation<Point, SegmentRatio> { enrichment_info<Point> enriched; visit_info visited; }; template <typename Point, typename SegmentRatio> struct traversal_turn_info : public turn_info < Point, SegmentRatio, traversal_turn_operation<Point, SegmentRatio> > {}; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP detail/overlay/overlay_type.hpp 0000644 00000003322 15125631657 0012735 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP namespace boost { namespace geometry { // TODO: move to detail enum overlay_type { overlay_union, overlay_intersection, overlay_difference, overlay_buffer, overlay_dissolve }; #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { enum operation_type { operation_none, operation_union, operation_intersection, operation_blocked, operation_continue, operation_opposite }; template <overlay_type OverlayType> struct operation_from_overlay { }; template <> struct operation_from_overlay<overlay_union> { static const operation_type value = operation_union; }; template <> struct operation_from_overlay<overlay_buffer> { static const operation_type value = operation_union; }; template <> struct operation_from_overlay<overlay_intersection> { static const operation_type value = operation_intersection; }; template <> struct operation_from_overlay<overlay_difference> { static const operation_type value = operation_intersection; }; template <> struct operation_from_overlay<overlay_dissolve> { static const operation_type value = operation_union; }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP detail/overlay/traversal_ring_creator.hpp 0000644 00000035741 15125631657 0014766 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP #include <cstddef> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp> #include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/traversal.hpp> #include <boost/geometry/algorithms/num_points.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/closure.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < bool Reverse1, bool Reverse2, overlay_type OverlayType, typename Geometry1, typename Geometry2, typename Turns, typename TurnInfoMap, typename Clusters, typename IntersectionStrategy, typename RobustPolicy, typename Visitor, typename Backtrack > struct traversal_ring_creator { typedef traversal < Reverse1, Reverse2, OverlayType, Geometry1, Geometry2, Turns, Clusters, RobustPolicy, typename IntersectionStrategy::side_strategy_type, Visitor > traversal_type; typedef typename boost::range_value<Turns>::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; static const operation_type target_operation = operation_from_overlay<OverlayType>::value; inline traversal_ring_creator(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, TurnInfoMap& turn_info_map, Clusters const& clusters, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Visitor& visitor) : m_trav(geometry1, geometry2, turns, clusters, robust_policy, intersection_strategy.get_side_strategy(), visitor) , m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) , m_turn_info_map(turn_info_map) , m_clusters(clusters) , m_intersection_strategy(intersection_strategy) , m_robust_policy(robust_policy) , m_visitor(visitor) { } template <typename Ring> inline traverse_error_type travel_to_next_turn(signed_size_type start_turn_index, int start_op_index, signed_size_type& turn_index, int& op_index, Ring& current_ring, bool is_start) { int const previous_op_index = op_index; signed_size_type const previous_turn_index = turn_index; turn_type& previous_turn = m_turns[turn_index]; turn_operation_type& previous_op = previous_turn.operations[op_index]; segment_identifier previous_seg_id; signed_size_type to_vertex_index = -1; if (! m_trav.select_turn_from_enriched(turn_index, previous_seg_id, to_vertex_index, start_turn_index, start_op_index, previous_turn, previous_op, is_start)) { return is_start ? traverse_error_no_next_ip_at_start : traverse_error_no_next_ip; } if (to_vertex_index >= 0) { if (previous_op.seg_id.source_index == 0) { geometry::copy_segments<Reverse1>(m_geometry1, previous_op.seg_id, to_vertex_index, m_intersection_strategy.get_side_strategy(), m_robust_policy, current_ring); } else { geometry::copy_segments<Reverse2>(m_geometry2, previous_op.seg_id, to_vertex_index, m_intersection_strategy.get_side_strategy(), m_robust_policy, current_ring); } } if (m_turns[turn_index].discarded) { return is_start ? traverse_error_dead_end_at_start : traverse_error_dead_end; } if (is_start) { // Register the start previous_op.visited.set_started(); m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start"); } if (! m_trav.select_turn(start_turn_index, start_op_index, turn_index, op_index, previous_op_index, previous_turn_index, previous_seg_id, is_start, current_ring.size() > 1)) { return is_start ? traverse_error_no_next_ip_at_start : traverse_error_no_next_ip; } { // Check operation (TODO: this might be redundant or should be catched before) const turn_type& current_turn = m_turns[turn_index]; const turn_operation_type& op = current_turn.operations[op_index]; if (op.visited.finalized() || m_trav.is_visited(current_turn, op, turn_index, op_index)) { return traverse_error_visit_again; } } // Update registration and append point turn_type& current_turn = m_turns[turn_index]; turn_operation_type& op = current_turn.operations[op_index]; detail::overlay::append_no_collinear(current_ring, current_turn.point, m_intersection_strategy.get_side_strategy(), m_robust_policy); // Register the visit m_trav.set_visited(current_turn, op); m_visitor.visit_traverse(m_turns, current_turn, op, "Visit"); return traverse_error_none; } template <typename Ring> inline traverse_error_type traverse(Ring& ring, signed_size_type start_turn_index, int start_op_index) { turn_type const& start_turn = m_turns[start_turn_index]; turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index]; detail::overlay::append_no_collinear(ring, start_turn.point, m_intersection_strategy.get_side_strategy(), m_robust_policy); signed_size_type current_turn_index = start_turn_index; int current_op_index = start_op_index; traverse_error_type error = travel_to_next_turn(start_turn_index, start_op_index, current_turn_index, current_op_index, ring, true); if (error != traverse_error_none) { // This is not necessarily a problem, it happens for clustered turns // which are "build in" or otherwise point inwards return error; } if (current_turn_index == start_turn_index) { start_op.visited.set_finished(); m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish"); return traverse_error_none; } if (start_turn.is_clustered()) { turn_type& turn = m_turns[current_turn_index]; turn_operation_type& op = turn.operations[current_op_index]; if (turn.cluster_id == start_turn.cluster_id && op.enriched.get_next_turn_index() == start_turn_index) { op.visited.set_finished(); m_visitor.visit_traverse(m_turns, m_turns[current_turn_index], start_op, "Early finish (cluster)"); return traverse_error_none; } } std::size_t const max_iterations = 2 + 2 * m_turns.size(); for (std::size_t i = 0; i <= max_iterations; i++) { // We assume clockwise polygons only, non self-intersecting, closed. // However, the input might be different, and checking validity // is up to the library user. // Therefore we make here some sanity checks. If the input // violates the assumptions, the output polygon will not be correct // but the routine will stop and output the current polygon, and // will continue with the next one. // Below three reasons to stop. error = travel_to_next_turn(start_turn_index, start_op_index, current_turn_index, current_op_index, ring, false); if (error != traverse_error_none) { return error; } if (current_turn_index == start_turn_index && current_op_index == start_op_index) { start_op.visited.set_finished(); m_visitor.visit_traverse(m_turns, start_turn, start_op, "Finish"); return traverse_error_none; } } return traverse_error_endless_loop; } template <typename Rings> void traverse_with_operation(turn_type const& start_turn, std::size_t turn_index, int op_index, Rings& rings, std::size_t& finalized_ring_size, typename Backtrack::state_type& state) { typedef typename boost::range_value<Rings>::type ring_type; turn_operation_type const& start_op = start_turn.operations[op_index]; if (! start_op.visited.none() || ! start_op.enriched.startable || start_op.visited.rejected() || ! (start_op.operation == target_operation || start_op.operation == detail::overlay::operation_continue)) { return; } ring_type ring; traverse_error_type traverse_error = traverse(ring, turn_index, op_index); if (traverse_error == traverse_error_none) { std::size_t const min_num_points = core_detail::closure::minimum_ring_size < geometry::closure<ring_type>::value >::value; if (geometry::num_points(ring) >= min_num_points) { clean_closing_dups_and_spikes(ring, m_intersection_strategy.get_side_strategy(), m_robust_policy); rings.push_back(ring); m_trav.finalize_visit_info(m_turn_info_map); finalized_ring_size++; } } else { Backtrack::apply( finalized_ring_size, rings, ring, m_turns, start_turn, m_turns[turn_index].operations[op_index], traverse_error, m_geometry1, m_geometry2, m_intersection_strategy, m_robust_policy, state, m_visitor); } } int get_operation_index(turn_type const& turn) const { // When starting with a continue operation, the one // with the smallest (for intersection) or largest (for union) // remaining distance (#8310b) // Also to avoid skipping a turn in between, which can happen // in rare cases (e.g. #130) static const bool is_union = operation_from_overlay<OverlayType>::value == operation_union; turn_operation_type const& op0 = turn.operations[0]; turn_operation_type const& op1 = turn.operations[1]; return op0.remaining_distance <= op1.remaining_distance ? (is_union ? 1 : 0) : (is_union ? 0 : 1); } template <typename Rings> void iterate(Rings& rings, std::size_t& finalized_ring_size, typename Backtrack::state_type& state) { for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { turn_type const& turn = m_turns[turn_index]; if (turn.discarded || turn.blocked()) { // Skip discarded and blocked turns continue; } if (turn.both(operation_continue)) { traverse_with_operation(turn, turn_index, get_operation_index(turn), rings, finalized_ring_size, state); } else { for (int op_index = 0; op_index < 2; op_index++) { traverse_with_operation(turn, turn_index, op_index, rings, finalized_ring_size, state); } } } } template <typename Rings> void iterate_with_preference(std::size_t phase, Rings& rings, std::size_t& finalized_ring_size, typename Backtrack::state_type& state) { for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index) { turn_type const& turn = m_turns[turn_index]; if (turn.discarded || turn.blocked()) { // Skip discarded and blocked turns continue; } turn_operation_type const& op0 = turn.operations[0]; turn_operation_type const& op1 = turn.operations[1]; if (phase == 0) { if (! op0.enriched.prefer_start && ! op1.enriched.prefer_start) { // Not preferred, take next one continue; } } if (turn.both(operation_continue)) { traverse_with_operation(turn, turn_index, get_operation_index(turn), rings, finalized_ring_size, state); } else { bool const forward = op0.enriched.prefer_start; int op_index = forward ? 0 : 1; int const increment = forward ? 1 : -1; for (int i = 0; i < 2; i++, op_index += increment) { traverse_with_operation(turn, turn_index, op_index, rings, finalized_ring_size, state); } } } } private: traversal_type m_trav; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; Turns& m_turns; TurnInfoMap& m_turn_info_map; // contains turn-info information per ring Clusters const& m_clusters; IntersectionStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; Visitor& m_visitor; }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_RING_CREATOR_HPP detail/overlay/do_reverse.hpp 0000644 00000002615 15125631657 0012354 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP #include <boost/geometry/core/point_order.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { // Metafunction helper for intersection and union template <order_selector Selector, bool Reverse = false> struct do_reverse {}; template <> struct do_reverse<clockwise, false> : std::false_type {}; template <> struct do_reverse<clockwise, true> : std::true_type {}; template <> struct do_reverse<counterclockwise, false> : std::true_type {}; template <> struct do_reverse<counterclockwise, true> : std::false_type {}; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DO_REVERSE_HPP detail/overlay/copy_segment_point.hpp 0000644 00000026202 15125631657 0014122 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP #include <boost/array.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/iterators/ever_circling_iterator.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace copy_segments { template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point_range { static inline bool apply(Range const& range, SegmentIdentifier const& seg_id, int offset, PointOut& point) { typedef typename closeable_view < Range const, closure<Range>::value >::type cview_type; typedef typename reversible_view < cview_type const, Reverse ? iterate_reverse : iterate_forward >::type rview_type; cview_type cview(range); rview_type view(cview); typedef typename boost::range_iterator<rview_type>::type iterator; geometry::ever_circling_iterator<iterator> it(boost::begin(view), boost::end(view), boost::begin(view) + seg_id.segment_index, true); for (signed_size_type i = 0; i < offset; ++i, ++it) { } geometry::convert(*it, point); return true; } }; template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point_polygon { static inline bool apply(Polygon const& polygon, SegmentIdentifier const& seg_id, int offset, PointOut& point) { // Call ring-version with the right ring return copy_segment_point_range < typename geometry::ring_type<Polygon>::type, Reverse, SegmentIdentifier, PointOut >::apply ( seg_id.ring_index < 0 ? geometry::exterior_ring(polygon) : range::at(geometry::interior_rings(polygon), seg_id.ring_index), seg_id, offset, point ); } }; template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point_box { static inline bool apply(Box const& box, SegmentIdentifier const& seg_id, int offset, PointOut& point) { signed_size_type index = seg_id.segment_index; for (int i = 0; i < offset; i++) { index++; } boost::array<typename point_type<Box>::type, 4> bp; assign_box_corners_oriented<Reverse>(box, bp); point = bp[index % 4]; return true; } }; template < typename MultiGeometry, typename SegmentIdentifier, typename PointOut, typename Policy > struct copy_segment_point_multi { static inline bool apply(MultiGeometry const& multi, SegmentIdentifier const& seg_id, int offset, PointOut& point) { BOOST_GEOMETRY_ASSERT ( seg_id.multi_index >= 0 && seg_id.multi_index < int(boost::size(multi)) ); // Call the single-version return Policy::apply(range::at(multi, seg_id.multi_index), seg_id, offset, point); } }; }} // namespace detail::copy_segments #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Tag, typename GeometryIn, bool Reverse, typename SegmentIdentifier, typename PointOut > struct copy_segment_point { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for this Geometry type.", Tag, GeometryIn); }; template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut> : detail::copy_segments::copy_segment_point_range < LineString, Reverse, SegmentIdentifier, PointOut > {}; template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut> : detail::copy_segments::copy_segment_point_range < Ring, Reverse, SegmentIdentifier, PointOut > {}; template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut> : detail::copy_segments::copy_segment_point_polygon < Polygon, Reverse, SegmentIdentifier, PointOut > {}; template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut> struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut> : detail::copy_segments::copy_segment_point_box < Box, Reverse, SegmentIdentifier, PointOut > {}; template < typename MultiGeometry, bool Reverse, typename SegmentIdentifier, typename PointOut > struct copy_segment_point < multi_polygon_tag, MultiGeometry, Reverse, SegmentIdentifier, PointOut > : detail::copy_segments::copy_segment_point_multi < MultiGeometry, SegmentIdentifier, PointOut, detail::copy_segments::copy_segment_point_polygon < typename boost::range_value<MultiGeometry>::type, Reverse, SegmentIdentifier, PointOut > > {}; template < typename MultiGeometry, bool Reverse, typename SegmentIdentifier, typename PointOut > struct copy_segment_point < multi_linestring_tag, MultiGeometry, Reverse, SegmentIdentifier, PointOut > : detail::copy_segments::copy_segment_point_multi < MultiGeometry, SegmentIdentifier, PointOut, detail::copy_segments::copy_segment_point_range < typename boost::range_value<MultiGeometry>::type, Reverse, SegmentIdentifier, PointOut > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief Helper function, copies a point from a segment \ingroup overlay */ template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut> inline bool copy_segment_point(Geometry const& geometry, SegmentIdentifier const& seg_id, int offset, PointOut& point_out) { concepts::check<Geometry const>(); return dispatch::copy_segment_point < typename tag<Geometry>::type, Geometry, Reverse, SegmentIdentifier, PointOut >::apply(geometry, seg_id, offset, point_out); } /*! \brief Helper function, to avoid the same construct several times, copies a point, based on a source-index and two geometries \ingroup overlay */ template < bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, typename SegmentIdentifier, typename PointOut > inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2, SegmentIdentifier const& seg_id, int offset, PointOut& point_out) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); BOOST_GEOMETRY_ASSERT(seg_id.source_index == 0 || seg_id.source_index == 1); if (seg_id.source_index == 0) { return dispatch::copy_segment_point < typename tag<Geometry1>::type, Geometry1, Reverse1, SegmentIdentifier, PointOut >::apply(geometry1, seg_id, offset, point_out); } else if (seg_id.source_index == 1) { return dispatch::copy_segment_point < typename tag<Geometry2>::type, Geometry2, Reverse2, SegmentIdentifier, PointOut >::apply(geometry2, seg_id, offset, point_out); } // Exception? return false; } /*! \brief Helper function, to avoid the same construct several times, copies a point, based on a source-index and two geometries \ingroup overlay */ template < bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, typename SegmentIdentifier, typename PointOut > inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2, SegmentIdentifier const& seg_id, PointOut& point1, PointOut& point2) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 0, point1) && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 1, point2); } /*! \brief Helper function, copies three points: two from the specified segment (from, to) and the next one \ingroup overlay */ template < bool Reverse1, bool Reverse2, typename Geometry1, typename Geometry2, typename SegmentIdentifier, typename PointOut > inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2, SegmentIdentifier const& seg_id, PointOut& point1, PointOut& point2, PointOut& point3) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 0, point1) && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 1, point2) && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, 2, point3); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP detail/overlay/get_turn_info.hpp 0000644 00000144340 15125631657 0013063 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2015, 2017, 2018, 2019. // Modifications copyright (c) 2015-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP #include <boost/core/ignore_unused.hpp> #include <boost/throw_exception.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/config.hpp> #include <boost/geometry/core/exception.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/policies/robustness/robust_point_type.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp> // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif namespace boost { namespace geometry { #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) class turn_info_exception : public geometry::exception { std::string message; public: // NOTE: "char" will be replaced by enum in future version inline turn_info_exception(char const method) { message = "Boost.Geometry Turn exception: "; message += method; } virtual ~turn_info_exception() throw() {} virtual char const* what() const throw() { return message.c_str(); } }; #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { struct base_turn_handler { // Returns true if both sides are opposite static inline bool opposite(int side1, int side2) { // We cannot state side1 == -side2, because 0 == -0 // So either side1*side2==-1 or side1==-side2 && side1 != 0 return side1 * side2 == -1; } // Same side of a segment (not being 0) static inline bool same(int side1, int side2) { return side1 * side2 == 1; } // Both get the same operation template <typename TurnInfo> static inline void both(TurnInfo& ti, operation_type const op) { ti.operations[0].operation = op; ti.operations[1].operation = op; } // If condition, first union/second intersection, else vice versa template <typename TurnInfo> static inline void ui_else_iu(bool condition, TurnInfo& ti) { ti.operations[0].operation = condition ? operation_union : operation_intersection; ti.operations[1].operation = condition ? operation_intersection : operation_union; } // If condition, both union, else both intersection template <typename TurnInfo> static inline void uu_else_ii(bool condition, TurnInfo& ti) { both(ti, condition ? operation_union : operation_intersection); } #if ! defined(BOOST_GEOMETRY_USE_RESCALING) template < typename UniqueSubRange1, typename UniqueSubRange2 > static inline int side_with_distance_measure(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, int range_index, int point_index) { if (range_index >= 1 && range_p.is_last_segment()) { return 0; } if (point_index >= 2 && range_q.is_last_segment()) { return 0; } typedef typename select_coordinate_type < typename UniqueSubRange1::point_type, typename UniqueSubRange2::point_type >::type coordinate_type; typedef detail::distance_measure<coordinate_type> dm_type; dm_type const dm = get_distance_measure(range_p.at(range_index), range_p.at(range_index + 1), range_q.at(point_index)); return dm.measure == 0 ? 0 : dm.measure > 0 ? 1 : -1; } template < typename UniqueSubRange1, typename UniqueSubRange2 > static inline int verified_side(int side, UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, int range_index, int point_index) { return side == 0 ? side_with_distance_measure(range_p, range_q, range_index, point_index) : side; } #else template <typename T1, typename T2> static inline int verified_side(int side, T1 const& , T2 const& , int , int) { return side; } #endif template <typename TurnInfo, typename IntersectionInfo> static inline void assign_point(TurnInfo& ti, method_type method, IntersectionInfo const& info, unsigned int index) { ti.method = method; BOOST_GEOMETRY_ASSERT(index < info.count); geometry::convert(info.intersections[index], ti.point); ti.operations[0].fraction = info.fractions[index].robust_ra; ti.operations[1].fraction = info.fractions[index].robust_rb; } template <typename TurnInfo, typename IntersectionInfo, typename DirInfo> static inline void assign_point_and_correct(TurnInfo& ti, method_type method, IntersectionInfo const& info, DirInfo const& dir_info) { ti.method = method; // For touch/touch interior always take the intersection point 0 (there is only one). static int const index = 0; geometry::convert(info.intersections[index], ti.point); for (int i = 0; i < 2; i++) { if (dir_info.arrival[i] == 1) { // The segment arrives at the intersection point, its fraction should be 1 // (due to precision it might be nearly so, but not completely, in rare cases) ti.operations[i].fraction = {1, 1}; } else if (dir_info.arrival[i] == -1) { // The segment leaves from the intersection point, likewise its fraction should be 0 ti.operations[i].fraction = {0, 1}; } else { ti.operations[i].fraction = i == 0 ? info.fractions[index].robust_ra : info.fractions[index].robust_rb; } } } template <typename IntersectionInfo> static inline unsigned int non_opposite_to_index(IntersectionInfo const& info) { return info.fractions[0].robust_rb < info.fractions[1].robust_rb ? 1 : 0; } template <typename Point1, typename Point2> static inline typename geometry::coordinate_type<Point1>::type distance_measure(Point1 const& a, Point2 const& b) { // TODO: use comparable distance for point-point instead - but that // causes currently cycling include problems typedef typename geometry::coordinate_type<Point1>::type ctype; ctype const dx = get<0>(a) - get<0>(b); ctype const dy = get<1>(a) - get<1>(b); return dx * dx + dy * dy; } template < std::size_t IndexP, std::size_t IndexQ, typename UniqueSubRange1, typename UniqueSubRange2, typename UmbrellaStrategy, typename TurnInfo > static inline void both_collinear( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, UmbrellaStrategy const&, std::size_t index_p, std::size_t index_q, TurnInfo& ti) { boost::ignore_unused(range_p, range_q); BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1); BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2); BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2); #if ! defined(BOOST_GEOMETRY_USE_RESCALING) ti.operations[IndexP].remaining_distance = distance_measure(ti.point, range_p.at(index_p)); ti.operations[IndexQ].remaining_distance = distance_measure(ti.point, range_q.at(index_q)); // pk/q2 is considered as collinear, but there might be // a tiny measurable difference. If so, use that. // Calculate pk // qj-qk typedef detail::distance_measure < typename select_coordinate_type < typename UniqueSubRange1::point_type, typename UniqueSubRange2::point_type >::type > dm_type; const bool p_closer = ti.operations[IndexP].remaining_distance < ti.operations[IndexQ].remaining_distance; dm_type const dm = p_closer ? get_distance_measure(range_q.at(index_q - 1), range_q.at(index_q), range_p.at(index_p)) : get_distance_measure(range_p.at(index_p - 1), range_p.at(index_p), range_q.at(index_q)); if (! dm.is_zero()) { // Not truely collinear, distinguish for union/intersection // If p goes left (positive), take that for a union bool p_left = p_closer ? dm.is_positive() : dm.is_negative(); ti.operations[IndexP].operation = p_left ? operation_union : operation_intersection; ti.operations[IndexQ].operation = p_left ? operation_intersection : operation_union; return; } #endif both(ti, operation_continue); } }; template < typename TurnInfo > struct touch_interior : public base_turn_handler { template < typename IntersectionInfo, typename UniqueSubRange > static bool handle_as_touch(IntersectionInfo const& info, UniqueSubRange const& non_touching_range) { #if defined(BOOST_GEOMETRY_USE_RESCALING) return false; #endif // // // ^ Q(i) ^ P(i) // \ / // \ / // \ / // \ / // \ / // \ / // \ / // \ / // \ / // \ / it is about buffer_rt_r // P(k) v/ they touch here "in the middle", but at the intersection... // <---------------->v there is no follow up IP // / // / // / // / // / // / // v Q(k) // // Measure where the IP is located. If it is really close to the end, // then there is no space for the next IP (on P(1)/Q(2). A "from" // intersection will be generated, but those are never handled. // Therefore handle it as a normal touch (two segments arrive at the // intersection point). It currently checks for zero, but even a // distance a little bit larger would do. typedef typename geometry::coordinate_type < typename UniqueSubRange::point_type >::type coor_t; coor_t const location = distance_measure(info.intersections[0], non_touching_range.at(1)); coor_t const zero = 0; bool const result = math::equals(location, zero); return result; } // Index: 0, P is the interior, Q is touching and vice versa template < unsigned int Index, typename UniqueSubRange1, typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SidePolicy, typename UmbrellaStrategy > static inline void apply(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& intersection_info, DirInfo const& dir_info, SidePolicy const& side, UmbrellaStrategy const& umbrella_strategy) { assign_point_and_correct(ti, method_touch_interior, intersection_info, dir_info); // Both segments of q touch segment p somewhere in its interior // 1) We know: if q comes from LEFT or RIGHT // (i.e. dir_info.sides.get<Index,0>() == 1 or -1) // 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR // and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i BOOST_STATIC_ASSERT(Index <= 1); static unsigned int const index_p = Index; static unsigned int const index_q = 1 - Index; bool const has_pk = ! range_p.is_last_segment(); bool const has_qk = ! range_q.is_last_segment(); int const side_qi_p = dir_info.sides.template get<index_q, 0>(); int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0; if (side_qi_p == -side_qk_p) { // Q crosses P from left->right or from right->left (test "ML1") // Union: folow P (left->right) or Q (right->left) // Intersection: other turn unsigned int index = side_qk_p == -1 ? index_p : index_q; ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; return; } int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0; // Only necessary if rescaling is turned off: int const side_pj_q2 = has_qk ? side.pj_wrt_q2() : 0; if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1) { // Q turns left on the right side of P (test "MR3") // Both directions for "intersection" both(ti, operation_intersection); ti.touch_only = true; } else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1) { if (has_qk && side_pj_q2 == -1) { // Q turns right on the left side of P (test "ML3") // Union: take both operations // Intersection: skip both(ti, operation_union); } else { // q2 is collinear with p1, so it does not turn back. This // can happen in floating point precision. In this case, // block one of the operations to avoid taking that path. ti.operations[index_p].operation = operation_union; ti.operations[index_q].operation = operation_blocked; } ti.touch_only = true; } else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q) { // Q turns left on the left side of P (test "ML2") // or Q turns right on the right side of P (test "MR2") // Union: take left turn (Q if Q turns left, P if Q turns right) // Intersection: other turn unsigned int index = side_qk_q == 1 ? index_q : index_p; if (has_qk && side_pj_q2 == 0) { // Even though sides xk w.r.t. 1 are distinct, pj is collinear // with q. Therefore swap the path index = 1 - index; } if (has_pk && has_qk && opposite(side_pj_q2, side_qi_p)) { // Without rescaling, floating point requires extra measures int const side_qj_p1 = side.qj_wrt_p1(); int const side_qj_p2 = side.qj_wrt_p2(); if (same(side_qj_p1, side_qj_p2)) { int const side_pj_q1 = side.pj_wrt_q1(); if (opposite(side_pj_q1, side_pj_q2)) { index = 1 - index; } } } ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; ti.touch_only = true; } else if (side_qk_p == 0) { // Q intersects on interior of P and continues collinearly if (side_qk_q == side_qi_p) { both_collinear<index_p, index_q>(range_p, range_q, umbrella_strategy, 1, 2, ti); } else { // Opposite direction, which is never travelled. // If Q turns left, P continues for intersection // If Q turns right, P continues for union ti.operations[index_p].operation = side_qk_q == 1 ? operation_intersection : operation_union; ti.operations[index_q].operation = operation_blocked; } } else { // Should not occur! ti.method = method_error; } } }; template < typename TurnInfo > struct touch : public base_turn_handler { static inline bool between(int side1, int side2, int turn) { return side1 == side2 && ! opposite(side1, turn); } #if ! defined(BOOST_GEOMETRY_USE_RESCALING) template < typename UniqueSubRange1, typename UniqueSubRange2 > static inline bool handle_imperfect_touch(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo& ti) { // Q // ^ // || // || // |^---- // >----->P // * * they touch here (P/Q are (nearly) on top) // // Q continues from where P comes. // P continues from where Q comes // This is often a blocking situation, // unless there are FP issues: there might be a distance // between Pj and Qj, in that case handle it as a union. // // Exaggerated: // Q // ^ Q is nearly vertical // \ but not completely - and still ends above P // | \qj In this case it should block P and // | ^------ set Q to Union // >----->P qj is LEFT of P1 and pi is LEFT of Q2 // (the other way round is also possible) typedef typename select_coordinate_type < typename UniqueSubRange1::point_type, typename UniqueSubRange2::point_type >::type coordinate_type; typedef detail::distance_measure<coordinate_type> dm_type; dm_type const dm_qj_p1 = get_distance_measure(range_p.at(0), range_p.at(1), range_q.at(1)); dm_type const dm_pi_q2 = get_distance_measure(range_q.at(1), range_q.at(2), range_p.at(0)); if (dm_qj_p1.measure > 0 && dm_pi_q2.measure > 0) { // Even though there is a touch, Q(j) is left of P1 // and P(i) is still left from Q2. // It can continue. ti.operations[0].operation = operation_blocked; // Q turns right -> union (both independent), // Q turns left -> intersection ti.operations[1].operation = operation_union; ti.touch_only = true; return true; } dm_type const dm_pj_q1 = get_distance_measure(range_q.at(0), range_q.at(1), range_p.at(1)); dm_type const dm_qi_p2 = get_distance_measure(range_p.at(1), range_p.at(2), range_q.at(0)); if (dm_pj_q1.measure > 0 && dm_qi_p2.measure > 0) { // Even though there is a touch, Q(j) is left of P1 // and P(i) is still left from Q2. // It can continue. ti.operations[0].operation = operation_union; // Q turns right -> union (both independent), // Q turns left -> intersection ti.operations[1].operation = operation_blocked; ti.touch_only = true; return true; } return false; } #endif template < typename UniqueSubRange1, typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SideCalculator, typename UmbrellaStrategy > static inline void apply(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& intersection_info, DirInfo const& dir_info, SideCalculator const& side, UmbrellaStrategy const& umbrella_strategy) { assign_point_and_correct(ti, method_touch, intersection_info, dir_info); bool const has_pk = ! range_p.is_last_segment(); bool const has_qk = ! range_q.is_last_segment(); int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0; int const side_qi_p1 = verified_side(dir_info.sides.template get<1, 0>(), range_p, range_q, 0, 0); int const side_qk_p1 = has_qk ? verified_side(side.qk_wrt_p1(), range_p, range_q, 0, 2) : 0; // If Qi and Qk are both at same side of Pi-Pj, // or collinear (so: not opposite sides) if (! opposite(side_qi_p1, side_qk_p1)) { int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0; int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0; int const side_qk_q = has_qk ? side.qk_wrt_q1() : 0; bool const q_turns_left = side_qk_q == 1; bool const block_q = side_qk_p1 == 0 && ! same(side_qi_p1, side_qk_q) ; // If Pk at same side as Qi/Qk // (the "or" is for collinear case) // or Q is fully collinear && P turns not to left if (side_pk_p == side_qi_p1 || side_pk_p == side_qk_p1 || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1)) { #if ! defined(BOOST_GEOMETRY_USE_RESCALING) if (side_qk_p1 == 0 && side_pk_q1 == 0 && has_qk && has_qk && handle_imperfect_touch(range_p, range_q, ti)) { // If q continues collinearly (opposite) with p, it should be blocked // but (FP) not if there is just a tiny space in between return; } #endif // Collinear -> lines join, continue // (#BRL2) if (side_pk_q2 == 0 && ! block_q) { both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti); return; } // Collinear opposite case -> block P // (#BRL4, #BLR8) if (side_pk_q1 == 0) { ti.operations[0].operation = operation_blocked; // Q turns right -> union (both independent), // Q turns left -> intersection ti.operations[1].operation = block_q ? operation_blocked : q_turns_left ? operation_intersection : operation_union; return; } // Pk between Qi and Qk // (#BRL3, #BRL7) if (between(side_pk_q1, side_pk_q2, side_qk_q)) { ui_else_iu(q_turns_left, ti); if (block_q) { ti.operations[1].operation = operation_blocked; } return; } // Pk between Qk and P, so left of Qk (if Q turns right) and vv // (#BRL1) if (side_pk_q2 == -side_qk_q) { ui_else_iu(! q_turns_left, ti); ti.touch_only = true; return; } // // (#BRL5, #BRL9) if (side_pk_q1 == -side_qk_q) { uu_else_ii(! q_turns_left, ti); if (block_q) { ti.operations[1].operation = operation_blocked; } else { ti.touch_only = true; } return; } } else { // Pk at other side than Qi/Pk ti.operations[0].operation = q_turns_left ? operation_intersection : operation_union; ti.operations[1].operation = block_q ? operation_blocked : side_qi_p1 == 1 || side_qk_p1 == 1 ? operation_union : operation_intersection; if (! block_q) { ti.touch_only = true; } return; } } else { // The qi/qk are opposite to each other, w.r.t. p1 // From left to right or from right to left int const side_pk_p = has_pk ? verified_side(side.pk_wrt_p1(), range_p, range_p, 0, 2) : 0; bool const right_to_left = side_qk_p1 == 1; // If p turns into direction of qi (1,2) if (side_pk_p == side_qi_p1) { int const side_pk_q1 = has_pk ? side.pk_wrt_q1() : 0; // Collinear opposite case -> block P if (side_pk_q1 == 0) { ti.operations[0].operation = operation_blocked; ti.operations[1].operation = right_to_left ? operation_union : operation_intersection; return; } if (side_pk_q1 == side_qk_p1) { uu_else_ii(right_to_left, ti); ti.touch_only = true; return; } } // If p turns into direction of qk (4,5) if (side_pk_p == side_qk_p1) { int const side_pk_q2 = has_pk ? side.pk_wrt_q2() : 0; // Collinear case -> lines join, continue if (side_pk_q2 == 0) { both(ti, operation_continue); return; } if (side_pk_q2 == side_qk_p1) { ui_else_iu(right_to_left, ti); ti.touch_only = true; return; } } // otherwise (3) ui_else_iu(! right_to_left, ti); return; } } }; template < typename TurnInfo > struct equal : public base_turn_handler { template < typename UniqueSubRange1, typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SideCalculator, typename UmbrellaStrategy > static inline void apply(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& info, DirInfo const& , SideCalculator const& side, UmbrellaStrategy const& umbrella_strategy) { // Copy the intersection point in TO direction assign_point(ti, method_equal, info, non_opposite_to_index(info)); bool const has_pk = ! range_p.is_last_segment(); bool const has_qk = ! range_q.is_last_segment(); int const side_pk_q2 = has_pk && has_qk ? side.pk_wrt_q2() : 0; int const side_pk_p = has_pk ? side.pk_wrt_p1() : 0; int const side_qk_p = has_qk ? side.qk_wrt_p1() : 0; #if ! defined(BOOST_GEOMETRY_USE_RESCALING) if (has_pk && has_qk && side_pk_p == side_qk_p) { // They turn to the same side, or continue both collinearly // Without rescaling, to check for union/intersection, // try to check side values (without any thresholds) typedef typename select_coordinate_type < typename UniqueSubRange1::point_type, typename UniqueSubRange2::point_type >::type coordinate_type; typedef detail::distance_measure<coordinate_type> dm_type; dm_type const dm_pk_q2 = get_distance_measure(range_q.at(1), range_q.at(2), range_p.at(2)); dm_type const dm_qk_p2 = get_distance_measure(range_p.at(1), range_p.at(2), range_q.at(2)); if (dm_qk_p2.measure != dm_pk_q2.measure) { // A (possibly very small) difference is detected, which // can be used to distinguish between union/intersection ui_else_iu(dm_qk_p2.measure < dm_pk_q2.measure, ti); return; } } #endif // If pk is collinear with qj-qk, they continue collinearly. // This can be on either side of p1 (== q1), or collinear // The second condition checks if they do not continue // oppositely if (side_pk_q2 == 0 && side_pk_p == side_qk_p) { both_collinear<0, 1>(range_p, range_q, umbrella_strategy, 2, 2, ti); return; } // If they turn to same side (not opposite sides) if (! opposite(side_pk_p, side_qk_p)) { // If pk is left of q2 or collinear: p: union, q: intersection ui_else_iu(side_pk_q2 != -1, ti); } else { // They turn opposite sides. If p turns left (or collinear), // p: union, q: intersection ui_else_iu(side_pk_p != -1, ti); } } }; template < typename TurnInfo > struct start : public base_turn_handler { template < typename UniqueSubRange1, typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SideCalculator, typename UmbrellaStrategy > static inline bool apply(UniqueSubRange1 const& /*range_p*/, UniqueSubRange2 const& /*range_q*/, TurnInfo& ti, IntersectionInfo const& info, DirInfo const& dir_info, SideCalculator const& side, UmbrellaStrategy const& ) { #if defined(BOOST_GEOMETRY_USE_RESCALING) // With rescaling, start turns are not needed. return false; #endif // Start turns have either how_a = -1, or how_b = -1 (either p leaves or q leaves) BOOST_GEOMETRY_ASSERT(dir_info.how_a != dir_info.how_b); BOOST_GEOMETRY_ASSERT(dir_info.how_a == -1 || dir_info.how_b == -1); BOOST_GEOMETRY_ASSERT(dir_info.how_a == 0 || dir_info.how_b == 0); if (dir_info.how_b == -1) { // p ---------------> // | // | q q leaves // v // int const side_qj_p1 = side.qj_wrt_p1(); ui_else_iu(side_qj_p1 == -1, ti); } else if (dir_info.how_a == -1) { // p leaves int const side_pj_q1 = side.pj_wrt_q1(); ui_else_iu(side_pj_q1 == 1, ti); } // Copy intersection point assign_point_and_correct(ti, method_start, info, dir_info); return true; } }; template < typename TurnInfo, typename AssignPolicy > struct equal_opposite : public base_turn_handler { template < typename UniqueSubRange1, typename UniqueSubRange2, typename OutputIterator, typename IntersectionInfo > static inline void apply( UniqueSubRange1 const& /*range_p*/, UniqueSubRange2 const& /*range_q*/, /* by value: */ TurnInfo tp, OutputIterator& out, IntersectionInfo const& intersection_info) { // For equal-opposite segments, normally don't do anything. if (AssignPolicy::include_opposite) { tp.method = method_equal; for (unsigned int i = 0; i < 2; i++) { tp.operations[i].operation = operation_opposite; } for (unsigned int i = 0; i < intersection_info.i_info().count; i++) { assign_point(tp, method_none, intersection_info.i_info(), i); *out++ = tp; } } } }; template < typename TurnInfo > struct collinear : public base_turn_handler { /* arrival P pk//p1 qk//q1 product* case result 1 1 1 CLL1 ui -1 1 -1 CLL2 iu 1 1 1 CLR1 ui -1 -1 1 CLR2 ui 1 -1 -1 CRL1 iu -1 1 -1 CRL2 iu 1 -1 -1 CRR1 iu -1 -1 1 CRR2 ui 1 0 0 CC1 cc -1 0 0 CC2 cc *product = arrival * (pk//p1 or qk//q1) Stated otherwise: - if P arrives: look at turn P - if Q arrives: look at turn Q - if P arrives and P turns left: union for P - if P arrives and P turns right: intersection for P - if Q arrives and Q turns left: union for Q (=intersection for P) - if Q arrives and Q turns right: intersection for Q (=union for P) ROBUSTNESS: p and q are collinear, so you would expect that side qk//p1 == pk//q1. But that is not always the case in near-epsilon ranges. Then decision logic is different. If p arrives, q is further, so the angle qk//p1 is (normally) more precise than pk//p1 */ template < typename UniqueSubRange1, typename UniqueSubRange2, typename IntersectionInfo, typename DirInfo, typename SidePolicy > static inline void apply( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo& ti, IntersectionInfo const& info, DirInfo const& dir_info, SidePolicy const& side) { // Copy the intersection point in TO direction assign_point(ti, method_collinear, info, non_opposite_to_index(info)); int const arrival = dir_info.arrival[0]; // Should not be 0, this is checked before BOOST_GEOMETRY_ASSERT(arrival != 0); bool const has_pk = ! range_p.is_last_segment(); bool const has_qk = ! range_q.is_last_segment(); int const side_p = has_pk ? side.pk_wrt_p1() : 0; int const side_q = has_qk ? side.qk_wrt_q1() : 0; // If p arrives, use p, else use q int const side_p_or_q = arrival == 1 ? side_p : side_q ; // See comments above, // resulting in a strange sort of mathematic rule here: // The arrival-info multiplied by the relevant side // delivers a consistent result. int const product = arrival * side_p_or_q; if(product == 0) { both(ti, operation_continue); } else { ui_else_iu(product == 1, ti); } // Calculate remaining distance. If it continues collinearly it is // measured until the end of the next segment ti.operations[0].remaining_distance = side_p == 0 && has_pk ? distance_measure(ti.point, range_p.at(2)) : distance_measure(ti.point, range_p.at(1)); ti.operations[1].remaining_distance = side_q == 0 && has_qk ? distance_measure(ti.point, range_q.at(2)) : distance_measure(ti.point, range_q.at(1)); } }; template < typename TurnInfo, typename AssignPolicy > struct collinear_opposite : public base_turn_handler { private : /* arrival P arrival Q pk//p1 qk//q1 case result2 result -------------------------------------------------------------- 1 1 1 -1 CLO1 ix xu 1 1 1 0 CLO2 ix (xx) 1 1 1 1 CLO3 ix xi 1 1 0 -1 CCO1 (xx) xu 1 1 0 0 CCO2 (xx) (xx) 1 1 0 1 CCO3 (xx) xi 1 1 -1 -1 CRO1 ux xu 1 1 -1 0 CRO2 ux (xx) 1 1 -1 1 CRO3 ux xi -1 1 -1 CXO1 xu -1 1 0 CXO2 (xx) -1 1 1 CXO3 xi 1 -1 1 CXO1 ix 1 -1 0 CXO2 (xx) 1 -1 -1 CXO3 ux */ template <unsigned int Index, typename IntersectionInfo> static inline bool set_tp(int side_rk_r, TurnInfo& tp, IntersectionInfo const& intersection_info) { BOOST_STATIC_ASSERT(Index <= 1); operation_type blocked = operation_blocked; switch(side_rk_r) { case 1 : // Turning left on opposite collinear: intersection tp.operations[Index].operation = operation_intersection; break; case -1 : // Turning right on opposite collinear: union tp.operations[Index].operation = operation_union; break; case 0 : // No turn on opposite collinear: block, do not traverse // But this "xx" is usually ignored, it is useless to include // two operations blocked, so the whole point does not need // to be generated. // So return false to indicate nothing is to be done. if (AssignPolicy::include_opposite) { tp.operations[Index].operation = operation_opposite; blocked = operation_opposite; } else { return false; } break; } // The other direction is always blocked when collinear opposite tp.operations[1 - Index].operation = blocked; // If P arrives within Q, set info on P (which is done above, index=0), // this turn-info belongs to the second intersection point, index=1 // (see e.g. figure CLO1) assign_point(tp, method_collinear, intersection_info, 1 - Index); return true; } public: static inline void empty_transformer(TurnInfo &) {} template < typename UniqueSubRange1, typename UniqueSubRange2, typename OutputIterator, typename IntersectionInfo, typename SidePolicy > static inline void apply( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, // Opposite collinear can deliver 2 intersection points, TurnInfo const& tp_model, OutputIterator& out, IntersectionInfo const& intersection_info, SidePolicy const& side) { apply(range_p, range_q, tp_model, out, intersection_info, side, empty_transformer); } template < typename UniqueSubRange1, typename UniqueSubRange2, typename OutputIterator, typename IntersectionInfo, typename SidePolicy, typename TurnTransformer > static inline void apply( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, // Opposite collinear can deliver 2 intersection points, TurnInfo const& tp_model, OutputIterator& out, IntersectionInfo const& info, SidePolicy const& side, TurnTransformer turn_transformer) { TurnInfo tp = tp_model; int const p_arrival = info.d_info().arrival[0]; int const q_arrival = info.d_info().arrival[1]; // If P arrives within Q, there is a turn dependent on P if ( p_arrival == 1 && ! range_p.is_last_segment() && set_tp<0>(side.pk_wrt_p1(), tp, info.i_info()) ) { turn_transformer(tp); *out++ = tp; } // If Q arrives within P, there is a turn dependent on Q if ( q_arrival == 1 && ! range_q.is_last_segment() && set_tp<1>(side.qk_wrt_q1(), tp, info.i_info()) ) { turn_transformer(tp); *out++ = tp; } if (AssignPolicy::include_opposite) { // Handle cases not yet handled above if ((q_arrival == -1 && p_arrival == 0) || (p_arrival == -1 && q_arrival == 0)) { for (unsigned int i = 0; i < 2; i++) { tp.operations[i].operation = operation_opposite; } for (unsigned int i = 0; i < info.i_info().count; i++) { assign_point(tp, method_collinear, info.i_info(), i); *out++ = tp; } } } } }; template < typename TurnInfo > struct crosses : public base_turn_handler { template <typename IntersectionInfo, typename DirInfo> static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info, DirInfo const& dir_info) { assign_point(ti, method_crosses, intersection_info, 0); // In all cases: // If Q crosses P from left to right // Union: take P // Intersection: take Q // Otherwise: vice versa int const side_qi_p1 = dir_info.sides.template get<1, 0>(); unsigned int const index = side_qi_p1 == 1 ? 0 : 1; ti.operations[index].operation = operation_union; ti.operations[1 - index].operation = operation_intersection; } }; struct only_convert : public base_turn_handler { template<typename TurnInfo, typename IntersectionInfo> static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info) { assign_point(ti, method_none, intersection_info, 0); ti.operations[0].operation = operation_continue; ti.operations[1].operation = operation_continue; } }; /*! \brief Policy doing nothing \details get_turn_info can have an optional policy include extra truns. By default it does not, and this class is that default. */ struct assign_null_policy { static bool const include_no_turn = false; static bool const include_degenerate = false; static bool const include_opposite = false; static bool const include_start_turn = false; }; struct assign_policy_only_start_turns { static bool const include_no_turn = false; static bool const include_degenerate = false; static bool const include_opposite = false; static bool const include_start_turn = true; }; /*! \brief Turn information: intersection point, method, and turn information \details Information necessary for traversal phase (a phase of the overlay process). The information is gathered during the get_turns (segment intersection) phase. \tparam AssignPolicy policy to assign extra info, e.g. to calculate distance from segment's first points to intersection points. It also defines if a certain class of points (degenerate, non-turns) should be included. */ template<typename AssignPolicy> struct get_turn_info { // Intersect a segment p with a segment q // Both p and q are modelled as sub_ranges to provide more points // to be able to give more information about the turn (left/right) template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnInfo, typename UmbrellaStrategy, typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, TurnInfo const& tp_model, UmbrellaStrategy const& umbrella_strategy, RobustPolicy const& robust_policy, OutputIterator out) { typedef intersection_info < UniqueSubRange1, UniqueSubRange2, typename TurnInfo::point_type, UmbrellaStrategy, RobustPolicy > inters_info; inters_info inters(range_p, range_q, umbrella_strategy, robust_policy); char const method = inters.d_info().how; if (method == 'd') { // Disjoint return out; } // Copy, to copy possibly extended fields TurnInfo tp = tp_model; bool const handle_as_touch_interior = method == 'm'; bool const handle_as_cross = method == 'i'; bool handle_as_touch = method == 't'; bool handle_as_equal = method == 'e'; bool const handle_as_collinear = method == 'c'; bool const handle_as_degenerate = method == '0'; bool const handle_as_start = method == 's'; // (angle, from) bool do_only_convert = method == 'a' || method == 'f'; if (handle_as_start) { // It is in some cases necessary to handle a start turn if (AssignPolicy::include_start_turn && start<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy)) { *out++ = tp; } else { do_only_convert = true; } } if (handle_as_touch_interior) { typedef touch_interior<TurnInfo> handler; if ( inters.d_info().arrival[1] == 1 ) { // Q arrives if (handler::handle_as_touch(inters.i_info(), range_p)) { handle_as_touch = true; } else { handler::template apply<0>(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); *out++ = tp; } } else { // P arrives, swap p/q if (handler::handle_as_touch(inters.i_info(), range_q)) { handle_as_touch = true; } else { handler::template apply<1>(range_q, range_p, tp, inters.i_info(), inters.d_info(), inters.get_swapped_sides(), umbrella_strategy); *out++ = tp; } } } if (handle_as_cross) { crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info()); *out++ = tp; } if (handle_as_touch) { // Touch: both segments arrive at the intersection point touch<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); *out++ = tp; } if (handle_as_collinear) { // Collinear if ( ! inters.d_info().opposite ) { if ( inters.d_info().arrival[0] == 0 ) { handle_as_equal = true; } else { collinear<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides()); *out++ = tp; } } else { collinear_opposite < TurnInfo, AssignPolicy >::apply(range_p, range_q, tp, out, inters, inters.sides()); // Zero, or two, turn points are assigned to *out++ } } if (handle_as_equal) { if ( ! inters.d_info().opposite ) { // Both equal // or collinear-and-ending at intersection point equal<TurnInfo>::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy); if (handle_as_collinear) { // Keep info as collinear, // so override already assigned method tp.method = method_collinear; } *out++ = tp; } else { equal_opposite < TurnInfo, AssignPolicy >::apply(range_p, range_q, tp, out, inters); // Zero, or two, turn points are assigned to *out++ } } if ((handle_as_degenerate && AssignPolicy::include_degenerate) || (do_only_convert && AssignPolicy::include_no_turn)) { if (inters.i_info().count > 0) { only_convert::apply(tp, inters.i_info()); *out++ = tp; } } return out; } }; }} // namespace detail::overlay #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #if defined(_MSC_VER) #pragma warning(pop) #endif #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP detail/overlay/get_turn_info_helpers.hpp 0000644 00000045312 15125631657 0014604 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP #include <boost/geometry/algorithms/detail/direction_code.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/recalculate.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/policies/relate/intersection_policy.hpp> #include <boost/geometry/policies/robustness/rescale_policy_tags.hpp> #include <boost/geometry/strategies/intersection_result.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { enum turn_position { position_middle, position_front, position_back }; template <typename Point, typename SegmentRatio> struct turn_operation_linear : public turn_operation<Point, SegmentRatio> { turn_operation_linear() : position(position_middle) , is_collinear(false) {} turn_position position; bool is_collinear; // valid only for Linear geometry }; template < typename TurnPointCSTag, typename UniqueSubRange1, typename UniqueSubRange2, typename SideStrategy > struct side_calculator { typedef typename UniqueSubRange1::point_type point1_type; typedef typename UniqueSubRange2::point_type point2_type; inline side_calculator(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, SideStrategy const& side_strategy) : m_side_strategy(side_strategy) , m_range_p(range_p) , m_range_q(range_q) {} inline int pk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_pk()); } inline int pk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pk()); } inline int qk_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qk()); } inline int qk_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_qk()); } inline int pk_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pk()); } inline int qk_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qk()); } // Necessary when rescaling turns off: inline int qj_wrt_p1() const { return m_side_strategy.apply(get_pi(), get_pj(), get_qj()); } inline int qj_wrt_p2() const { return m_side_strategy.apply(get_pj(), get_pk(), get_qj()); } inline int pj_wrt_q1() const { return m_side_strategy.apply(get_qi(), get_qj(), get_pj()); } inline int pj_wrt_q2() const { return m_side_strategy.apply(get_qj(), get_qk(), get_pj()); } inline point1_type const& get_pi() const { return m_range_p.at(0); } inline point1_type const& get_pj() const { return m_range_p.at(1); } inline point1_type const& get_pk() const { return m_range_p.at(2); } inline point2_type const& get_qi() const { return m_range_q.at(0); } inline point2_type const& get_qj() const { return m_range_q.at(1); } inline point2_type const& get_qk() const { return m_range_q.at(2); } // Used side-strategy, owned by the calculator, // created from .get_side_strategy() SideStrategy m_side_strategy; // Used ranges - owned by get_turns or (for robust points) by intersection_info_base UniqueSubRange1 const& m_range_p; UniqueSubRange2 const& m_range_q; }; template<typename Point, typename UniqueSubRange, typename RobustPolicy> struct robust_subrange_adapter { typedef Point point_type; robust_subrange_adapter(UniqueSubRange const& unique_sub_range, Point const& robust_point_i, Point const& robust_point_j, RobustPolicy const& robust_policy) : m_unique_sub_range(unique_sub_range) , m_robust_policy(robust_policy) , m_robust_point_i(robust_point_i) , m_robust_point_j(robust_point_j) , m_k_retrieved(false) {} std::size_t size() const { return m_unique_sub_range.size(); } //! Get precalculated point Point const& at(std::size_t index) const { BOOST_GEOMETRY_ASSERT(index < size()); switch (index) { case 0 : return m_robust_point_i; case 1 : return m_robust_point_j; case 2 : return get_point_k(); default : return m_robust_point_i; } } private : Point const& get_point_k() const { if (! m_k_retrieved) { geometry::recalculate(m_robust_point_k, m_unique_sub_range.at(2), m_robust_policy); m_k_retrieved = true; } return m_robust_point_k; } UniqueSubRange const& m_unique_sub_range; RobustPolicy const& m_robust_policy; Point const& m_robust_point_i; Point const& m_robust_point_j; mutable Point m_robust_point_k; mutable bool m_k_retrieved; }; template < typename UniqueSubRange1, typename UniqueSubRange2, typename RobustPolicy > struct robust_point_calculator { typedef typename geometry::robust_point_type < typename UniqueSubRange1::point_type, RobustPolicy >::type robust_point1_type; typedef typename geometry::robust_point_type < typename UniqueSubRange2::point_type, RobustPolicy >::type robust_point2_type; inline robust_point_calculator(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, RobustPolicy const& robust_policy) : m_robust_policy(robust_policy) , m_range_p(range_p) , m_range_q(range_q) , m_pk_retrieved(false) , m_qk_retrieved(false) { // Calculate pi,pj and qi,qj which are almost always necessary // But don't calculate pk/qk yet, which is retrieved (taking // more time) and not always necessary. geometry::recalculate(m_rpi, range_p.at(0), robust_policy); geometry::recalculate(m_rpj, range_p.at(1), robust_policy); geometry::recalculate(m_rqi, range_q.at(0), robust_policy); geometry::recalculate(m_rqj, range_q.at(1), robust_policy); } inline robust_point1_type const& get_rpk() const { if (! m_pk_retrieved) { geometry::recalculate(m_rpk, m_range_p.at(2), m_robust_policy); m_pk_retrieved = true; } return m_rpk; } inline robust_point2_type const& get_rqk() const { if (! m_qk_retrieved) { geometry::recalculate(m_rqk, m_range_q.at(2), m_robust_policy); m_qk_retrieved = true; } return m_rqk; } robust_point1_type m_rpi, m_rpj; robust_point2_type m_rqi, m_rqj; private : RobustPolicy const& m_robust_policy; UniqueSubRange1 const& m_range_p; UniqueSubRange2 const& m_range_q; // On retrieval mutable robust_point1_type m_rpk; mutable robust_point2_type m_rqk; mutable bool m_pk_retrieved; mutable bool m_qk_retrieved; }; // Default version (empty - specialized below) template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnPoint, typename UmbrellaStrategy, typename RobustPolicy, typename Tag = typename rescale_policy_type<RobustPolicy>::type > class intersection_info_base {}; // Version with rescaling, having robust points template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnPoint, typename UmbrellaStrategy, typename RobustPolicy > class intersection_info_base<UniqueSubRange1, UniqueSubRange2, TurnPoint, UmbrellaStrategy, RobustPolicy, rescale_policy_tag> { typedef robust_point_calculator < UniqueSubRange1, UniqueSubRange2, RobustPolicy > robust_calc_type; public: typedef segment_intersection_points < TurnPoint, geometry::segment_ratio<boost::long_long_type> > intersection_point_type; typedef policies::relate::segments_intersection_policy < intersection_point_type > intersection_policy_type; typedef typename intersection_policy_type::return_type result_type; typedef typename robust_calc_type::robust_point1_type robust_point1_type; typedef typename robust_calc_type::robust_point2_type robust_point2_type; typedef robust_subrange_adapter<robust_point1_type, UniqueSubRange1, RobustPolicy> robust_subrange1; typedef robust_subrange_adapter<robust_point2_type, UniqueSubRange2, RobustPolicy> robust_subrange2; typedef typename cs_tag<TurnPoint>::type cs_tag; typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type; typedef side_calculator<cs_tag, robust_subrange1, robust_subrange2, side_strategy_type> side_calculator_type; typedef side_calculator < cs_tag, robust_subrange2, robust_subrange1, side_strategy_type > robust_swapped_side_calculator_type; intersection_info_base(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, UmbrellaStrategy const& umbrella_strategy, RobustPolicy const& robust_policy) : m_range_p(range_p) , m_range_q(range_q) , m_robust_calc(range_p, range_q, robust_policy) , m_robust_range_p(range_p, m_robust_calc.m_rpi, m_robust_calc.m_rpj, robust_policy) , m_robust_range_q(range_q, m_robust_calc.m_rqi, m_robust_calc.m_rqj, robust_policy) , m_side_calc(m_robust_range_p, m_robust_range_q, umbrella_strategy.get_side_strategy()) , m_result(umbrella_strategy.apply(range_p, range_q, intersection_policy_type(), m_robust_range_p, m_robust_range_q)) {} inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); } inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); } inline robust_point1_type const& rpi() const { return m_robust_calc.m_rpi; } inline robust_point1_type const& rpj() const { return m_robust_calc.m_rpj; } inline robust_point1_type const& rpk() const { return m_robust_calc.get_rpk(); } inline robust_point2_type const& rqi() const { return m_robust_calc.m_rqi; } inline robust_point2_type const& rqj() const { return m_robust_calc.m_rqj; } inline robust_point2_type const& rqk() const { return m_robust_calc.get_rqk(); } inline side_calculator_type const& sides() const { return m_side_calc; } robust_swapped_side_calculator_type get_swapped_sides() const { robust_swapped_side_calculator_type result( m_robust_range_q, m_robust_range_p, m_side_calc.m_side_strategy); return result; } private : // Owned by get_turns UniqueSubRange1 const& m_range_p; UniqueSubRange2 const& m_range_q; // Owned by this class robust_calc_type m_robust_calc; robust_subrange1 m_robust_range_p; robust_subrange2 m_robust_range_q; side_calculator_type m_side_calc; protected : result_type m_result; }; // Version without rescaling template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnPoint, typename UmbrellaStrategy, typename RobustPolicy > class intersection_info_base<UniqueSubRange1, UniqueSubRange2, TurnPoint, UmbrellaStrategy, RobustPolicy, no_rescale_policy_tag> { public: typedef segment_intersection_points<TurnPoint> intersection_point_type; typedef policies::relate::segments_intersection_policy < intersection_point_type > intersection_policy_type; typedef typename intersection_policy_type::return_type result_type; typedef typename UniqueSubRange1::point_type point1_type; typedef typename UniqueSubRange2::point_type point2_type; typedef typename UmbrellaStrategy::cs_tag cs_tag; typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type; typedef side_calculator<cs_tag, UniqueSubRange1, UniqueSubRange2, side_strategy_type> side_calculator_type; typedef side_calculator < cs_tag, UniqueSubRange2, UniqueSubRange1, side_strategy_type > swapped_side_calculator_type; intersection_info_base(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, UmbrellaStrategy const& umbrella_strategy, no_rescale_policy const& ) : m_range_p(range_p) , m_range_q(range_q) , m_side_calc(range_p, range_q, umbrella_strategy.get_side_strategy()) , m_result(umbrella_strategy.apply(range_p, range_q, intersection_policy_type())) {} inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); } inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); } inline point1_type const& rpi() const { return m_side_calc.get_pi(); } inline point1_type const& rpj() const { return m_side_calc.get_pj(); } inline point1_type const& rpk() const { return m_side_calc.get_pk(); } inline point2_type const& rqi() const { return m_side_calc.get_qi(); } inline point2_type const& rqj() const { return m_side_calc.get_qj(); } inline point2_type const& rqk() const { return m_side_calc.get_qk(); } inline side_calculator_type const& sides() const { return m_side_calc; } swapped_side_calculator_type get_swapped_sides() const { swapped_side_calculator_type result( m_range_q, m_range_p, m_side_calc.m_side_strategy); return result; } private : // Owned by get_turns UniqueSubRange1 const& m_range_p; UniqueSubRange2 const& m_range_q; // Owned by this class side_calculator_type m_side_calc; protected : result_type m_result; }; template < typename UniqueSubRange1, typename UniqueSubRange2, typename TurnPoint, typename UmbrellaStrategy, typename RobustPolicy > class intersection_info : public intersection_info_base<UniqueSubRange1, UniqueSubRange2, TurnPoint, UmbrellaStrategy, RobustPolicy> { typedef intersection_info_base<UniqueSubRange1, UniqueSubRange2, TurnPoint, UmbrellaStrategy, RobustPolicy> base; public: typedef typename UniqueSubRange1::point_type point1_type; typedef typename UniqueSubRange2::point_type point2_type; typedef UmbrellaStrategy intersection_strategy_type; typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type; typedef typename UmbrellaStrategy::cs_tag cs_tag; typedef typename base::side_calculator_type side_calculator_type; typedef typename base::result_type result_type; typedef typename result_type::intersection_points_type i_info_type; typedef typename result_type::direction_type d_info_type; intersection_info(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, UmbrellaStrategy const& umbrella_strategy, RobustPolicy const& robust_policy) : base(range_p, range_q, umbrella_strategy, robust_policy) , m_intersection_strategy(umbrella_strategy) , m_robust_policy(robust_policy) {} inline result_type const& result() const { return base::m_result; } inline i_info_type const& i_info() const { return base::m_result.intersection_points; } inline d_info_type const& d_info() const { return base::m_result.direction; } inline side_strategy_type get_side_strategy() const { return m_intersection_strategy.get_side_strategy(); } // TODO: it's more like is_spike_ip_p inline bool is_spike_p() const { if (base::p_is_last_segment()) { return false; } if (base::sides().pk_wrt_p1() == 0) { // p: pi--------pj--------pk // or: pi----pk==pj if (! is_ip_j<0>()) { return false; } // TODO: why is q used to determine spike property in p? bool const has_qk = ! base::q_is_last_segment(); int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0; int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0; if (qk_p1 == -qk_p2) { if (qk_p1 == 0) { // qk is collinear with both p1 and p2, // verify if pk goes backwards w.r.t. pi/pj return direction_code<cs_tag>(base::rpi(), base::rpj(), base::rpk()) == -1; } // qk is at opposite side of p1/p2, therefore // p1/p2 (collinear) are opposite and form a spike return true; } } return false; } inline bool is_spike_q() const { if (base::q_is_last_segment()) { return false; } // See comments at is_spike_p if (base::sides().qk_wrt_q1() == 0) { if (! is_ip_j<1>()) { return false; } // TODO: why is p used to determine spike property in q? bool const has_pk = ! base::p_is_last_segment(); int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0; int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0; if (pk_q1 == -pk_q2) { if (pk_q1 == 0) { return direction_code<cs_tag>(base::rqi(), base::rqj(), base::rqk()) == -1; } return true; } } return false; } private: template <std::size_t OpId> bool is_ip_j() const { int arrival = d_info().arrival[OpId]; bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0; if (same_dirs) { if (i_info().count == 2) { return arrival != -1; } else { return arrival == 0; } } else { return arrival == 1; } } UmbrellaStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP detail/overlay/linear_linear.hpp 0000644 00000022663 15125631657 0013030 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_OVERLAY_LINEAR_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP #include <algorithm> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/relate/turns.hpp> #include <boost/geometry/algorithms/detail/turns/compare_turns.hpp> #include <boost/geometry/algorithms/detail/turns/filter_continue_turns.hpp> #include <boost/geometry/algorithms/detail/turns/remove_duplicate_turns.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp> #include <boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp> #include <boost/geometry/algorithms/convert.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { template < typename LineStringOut, overlay_type OverlayType, typename Geometry, typename GeometryTag > struct linear_linear_no_intersections; template <typename LineStringOut, typename LineString> struct linear_linear_no_intersections < LineStringOut, overlay_difference, LineString, linestring_tag > { template <typename OutputIterator> static inline OutputIterator apply(LineString const& linestring, OutputIterator oit) { LineStringOut ls_out; geometry::convert(linestring, ls_out); *oit++ = ls_out; return oit; } }; template <typename LineStringOut, typename MultiLineString> struct linear_linear_no_intersections < LineStringOut, overlay_difference, MultiLineString, multi_linestring_tag > { template <typename OutputIterator> static inline OutputIterator apply(MultiLineString const& multilinestring, OutputIterator oit) { for (typename boost::range_iterator<MultiLineString const>::type it = boost::begin(multilinestring); it != boost::end(multilinestring); ++it) { LineStringOut ls_out; geometry::convert(*it, ls_out); *oit++ = ls_out; } return oit; } }; template <typename LineStringOut, typename Geometry, typename GeometryTag> struct linear_linear_no_intersections < LineStringOut, overlay_intersection, Geometry, GeometryTag > { template <typename OutputIterator> static inline OutputIterator apply(Geometry const&, OutputIterator oit) { return oit; } }; template < typename Linear1, typename Linear2, typename LinestringOut, overlay_type OverlayType, bool EnableFilterContinueTurns = false, bool EnableRemoveDuplicateTurns = false, bool EnableDegenerateTurns = true, #ifdef BOOST_GEOMETRY_INTERSECTION_DO_NOT_INCLUDE_ISOLATED_POINTS bool EnableFollowIsolatedPoints = false #else bool EnableFollowIsolatedPoints = true #endif > class linear_linear_linestring { protected: struct assign_policy { static bool const include_no_turn = false; static bool const include_degenerate = EnableDegenerateTurns; static bool const include_opposite = false; static bool const include_start_turn = false; }; template < typename Turns, typename LinearGeometry1, typename LinearGeometry2, typename IntersectionStrategy, typename RobustPolicy > static inline void compute_turns(Turns& turns, LinearGeometry1 const& linear1, LinearGeometry2 const& linear2, IntersectionStrategy const& strategy, RobustPolicy const& robust_policy) { turns.clear(); detail::get_turns::no_interrupt_policy interrupt_policy; geometry::detail::relate::turns::get_turns < LinearGeometry1, LinearGeometry2, detail::get_turns::get_turn_info_type < LinearGeometry1, LinearGeometry2, assign_policy > >::apply(turns, linear1, linear2, interrupt_policy, strategy, robust_policy); } template < overlay_type OverlayTypeForFollow, bool FollowIsolatedPoints, typename Turns, typename LinearGeometry1, typename LinearGeometry2, typename OutputIterator, typename IntersectionStrategy > static inline OutputIterator sort_and_follow_turns(Turns& turns, LinearGeometry1 const& linear1, LinearGeometry2 const& linear2, OutputIterator oit, IntersectionStrategy const& strategy) { // remove turns that have no added value turns::filter_continue_turns < Turns, EnableFilterContinueTurns && OverlayType != overlay_intersection >::apply(turns); // sort by seg_id, distance, and operation std::sort(boost::begin(turns), boost::end(turns), detail::turns::less_seg_fraction_other_op<>()); // remove duplicate turns turns::remove_duplicate_turns < Turns, EnableRemoveDuplicateTurns >::apply(turns); return detail::overlay::following::linear::follow < LinestringOut, LinearGeometry1, LinearGeometry2, OverlayTypeForFollow, FollowIsolatedPoints, !EnableFilterContinueTurns || OverlayType == overlay_intersection >::apply(linear1, linear2, boost::begin(turns), boost::end(turns), oit, strategy.get_side_strategy()); } public: template < typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linear1 const& linear1, Linear2 const& linear2, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { typedef typename detail::relate::turns::get_turns < Linear1, Linear2, detail::get_turns::get_turn_info_type < Linear1, Linear2, assign_policy > >::template turn_info_type<Strategy, RobustPolicy>::type turn_info; typedef std::vector<turn_info> turns_container; turns_container turns; compute_turns(turns, linear1, linear2, strategy, robust_policy); if ( turns.empty() ) { // the two linear geometries are disjoint return linear_linear_no_intersections < LinestringOut, OverlayType, Linear1, typename tag<Linear1>::type >::apply(linear1, oit); } return sort_and_follow_turns < OverlayType, EnableFollowIsolatedPoints && OverlayType == overlay_intersection >(turns, linear1, linear2, oit, strategy); } }; template < typename Linear1, typename Linear2, typename LinestringOut, bool EnableFilterContinueTurns, bool EnableRemoveDuplicateTurns, bool EnableDegenerateTurns, bool EnableFollowIsolatedPoints > struct linear_linear_linestring < Linear1, Linear2, LinestringOut, overlay_union, EnableFilterContinueTurns, EnableRemoveDuplicateTurns, EnableDegenerateTurns, EnableFollowIsolatedPoints > { template < typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linear1 const& linear1, Linear2 const& linear2, RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { oit = linear_linear_no_intersections < LinestringOut, overlay_difference, Linear1, typename tag<Linear1>::type >::apply(linear1, oit); return linear_linear_linestring < Linear2, Linear1, LinestringOut, overlay_difference, EnableFilterContinueTurns, EnableRemoveDuplicateTurns, EnableDegenerateTurns, EnableFollowIsolatedPoints >::apply(linear2, linear1, robust_policy, oit, strategy); } }; }} // namespace detail::overlay #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_LINEAR_LINEAR_HPP detail/ring_identifier.hpp 0000644 00000004355 15125631657 0011702 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP #if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER) #include <iostream> #endif #include <boost/geometry/algorithms/detail/signed_size_type.hpp> namespace boost { namespace geometry { // Ring Identifier. It is currently: source,multi,ring struct ring_identifier { inline ring_identifier() : source_index(-1) , multi_index(-1) , ring_index(-1) {} inline ring_identifier(signed_size_type src, signed_size_type mul, signed_size_type rin) : source_index(src) , multi_index(mul) , ring_index(rin) {} inline bool operator<(ring_identifier const& other) const { return source_index != other.source_index ? source_index < other.source_index : multi_index !=other.multi_index ? multi_index < other.multi_index : ring_index < other.ring_index ; } inline bool operator==(ring_identifier const& other) const { return source_index == other.source_index && ring_index == other.ring_index && multi_index == other.multi_index ; } inline bool operator!=(ring_identifier const& other) const { return ! operator==(other); } #if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER) friend std::ostream& operator<<(std::ostream &os, ring_identifier const& ring_id) { os << "(s:" << ring_id.source_index; if (ring_id.ring_index >= 0) os << ", r:" << ring_id.ring_index; if (ring_id.multi_index >= 0) os << ", m:" << ring_id.multi_index; os << ")"; return os; } #endif signed_size_type source_index; signed_size_type multi_index; signed_size_type ring_index; }; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP detail/make/make.hpp 0000644 00000004336 15125631657 0010372 0 ustar 00 // Boost.Geometry // Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP #include <boost/geometry/geometries/infinite_line.hpp> #include <boost/geometry/core/access.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace make { template <typename Type, typename Coordinate> inline model::infinite_line<Type> make_infinite_line(Coordinate const& x1, Coordinate const& y1, Coordinate const& x2, Coordinate const& y2) { model::infinite_line<Type> result; result.a = y1 - y2; result.b = x2 - x1; result.c = -result.a * x1 - result.b * y1; return result; } template <typename Type, typename Point> inline model::infinite_line<Type> make_infinite_line(Point const& a, Point const& b) { return make_infinite_line<Type>(geometry::get<0>(a), geometry::get<1>(a), geometry::get<0>(b), geometry::get<1>(b)); } template <typename Type, typename Segment> inline model::infinite_line<Type> make_infinite_line(Segment const& segment) { return make_infinite_line<Type>(geometry::get<0, 0>(segment), geometry::get<0, 1>(segment), geometry::get<1, 0>(segment), geometry::get<1, 1>(segment)); } template <typename Type, typename Point> inline model::infinite_line<Type> make_perpendicular_line(Point const& a, Point const& b, Point const& c) { // https://www.math-only-math.com/equation-of-a-line-perpendicular-to-a-line.html model::infinite_line<Type> const line = make_infinite_line<Type>(a, b); model::infinite_line<Type> result; result.a = line.b; result.b = -line.a; // Lines with any result.c are perpendicular to a->b // Calculate this result such that it goes through point c result.c = -result.a * geometry::get<0>(c) - result.b * geometry::get<1>(c); return result; } }} // namespace detail::make #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP detail/closest_feature/geometry_to_range.hpp 0000644 00000010074 15125631657 0015434 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP #include <iterator> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace closest_feature { // returns the range iterator the realizes the closest // distance between the geometry and the element of the range class geometry_to_range { private: template < typename Geometry, typename RangeIterator, typename Strategy, typename Distance > static inline void apply(Geometry const& geometry, RangeIterator first, RangeIterator last, Strategy const& strategy, RangeIterator& it_min, Distance& dist_min) { BOOST_GEOMETRY_ASSERT( first != last ); Distance const zero = Distance(0); // start with first distance it_min = first; dist_min = dispatch::distance < Geometry, typename std::iterator_traits<RangeIterator>::value_type, Strategy >::apply(geometry, *it_min, strategy); // check if other elements in the range are closer for (RangeIterator it = ++first; it != last; ++it) { Distance dist = dispatch::distance < Geometry, typename std::iterator_traits<RangeIterator>::value_type, Strategy >::apply(geometry, *it, strategy); if (geometry::math::equals(dist, zero)) { dist_min = dist; it_min = it; return; } else if (dist < dist_min) { dist_min = dist; it_min = it; } } } public: template < typename Geometry, typename RangeIterator, typename Strategy, typename Distance > static inline RangeIterator apply(Geometry const& geometry, RangeIterator first, RangeIterator last, Strategy const& strategy, Distance& dist_min) { RangeIterator it_min; apply(geometry, first, last, strategy, it_min, dist_min); return it_min; } template < typename Geometry, typename RangeIterator, typename Strategy > static inline RangeIterator apply(Geometry const& geometry, RangeIterator first, RangeIterator last, Strategy const& strategy) { typename strategy::distance::services::return_type < Strategy, typename point_type<Geometry>::type, typename point_type < typename std::iterator_traits < RangeIterator >::value_type >::type >::type dist_min; return apply(geometry, first, last, strategy, dist_min); } }; }} // namespace detail::closest_feature #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP detail/closest_feature/range_to_range.hpp 0000644 00000014646 15125631657 0014706 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, 2019, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP #include <cstddef> #include <iterator> #include <utility> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/algorithms/dispatch/distance.hpp> #include <boost/geometry/index/rtree.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace closest_feature { // returns a pair of a objects where the first is an object of the // r-tree range and the second an object of the query range that // realizes the closest feature of the two ranges class range_to_range_rtree { private: template < typename RTreeRangeIterator, typename QueryRangeIterator, typename Strategy, typename RTreeValueType, typename Distance > static inline void apply(RTreeRangeIterator rtree_first, RTreeRangeIterator rtree_last, QueryRangeIterator queries_first, QueryRangeIterator queries_last, Strategy const& strategy, RTreeValueType& rtree_min, QueryRangeIterator& qit_min, Distance& dist_min) { typedef strategy::index::services::from_strategy < Strategy > index_strategy_from; typedef index::parameters < index::linear<8>, typename index_strategy_from::type > index_parameters_type; typedef index::rtree<RTreeValueType, index_parameters_type> rtree_type; BOOST_GEOMETRY_ASSERT( rtree_first != rtree_last ); BOOST_GEOMETRY_ASSERT( queries_first != queries_last ); Distance const zero = Distance(0); dist_min = zero; // create -- packing algorithm rtree_type rt(rtree_first, rtree_last, index_parameters_type(index::linear<8>(), index_strategy_from::get(strategy))); RTreeValueType t_v; bool first = true; for (QueryRangeIterator qit = queries_first; qit != queries_last; ++qit, first = false) { std::size_t n = rt.query(index::nearest(*qit, 1), &t_v); BOOST_GEOMETRY_ASSERT( n > 0 ); // n above is unused outside BOOST_GEOMETRY_ASSERT, // hence the call to boost::ignore_unused below // // however, t_v (initialized by the call to rt.query(...)) // is used below, which is why we cannot put the call to // rt.query(...) inside BOOST_GEOMETRY_ASSERT boost::ignore_unused(n); Distance dist = dispatch::distance < RTreeValueType, typename std::iterator_traits < QueryRangeIterator >::value_type, Strategy >::apply(t_v, *qit, strategy); if (first || dist < dist_min) { dist_min = dist; rtree_min = t_v; qit_min = qit; if ( math::equals(dist_min, zero) ) { return; } } } } public: template <typename RTreeRangeIterator, typename QueryRangeIterator> struct return_type { typedef std::pair < typename std::iterator_traits<RTreeRangeIterator>::value_type, QueryRangeIterator > type; }; template < typename RTreeRangeIterator, typename QueryRangeIterator, typename Strategy, typename Distance > static inline typename return_type < RTreeRangeIterator, QueryRangeIterator >::type apply(RTreeRangeIterator rtree_first, RTreeRangeIterator rtree_last, QueryRangeIterator queries_first, QueryRangeIterator queries_last, Strategy const& strategy, Distance& dist_min) { typedef typename std::iterator_traits < RTreeRangeIterator >::value_type rtree_value_type; rtree_value_type rtree_min; QueryRangeIterator qit_min; apply(rtree_first, rtree_last, queries_first, queries_last, strategy, rtree_min, qit_min, dist_min); return std::make_pair(rtree_min, qit_min); } template < typename RTreeRangeIterator, typename QueryRangeIterator, typename Strategy > static inline typename return_type < RTreeRangeIterator, QueryRangeIterator >::type apply(RTreeRangeIterator rtree_first, RTreeRangeIterator rtree_last, QueryRangeIterator queries_first, QueryRangeIterator queries_last, Strategy const& strategy) { typedef typename std::iterator_traits < RTreeRangeIterator >::value_type rtree_value_type; typename strategy::distance::services::return_type < Strategy, typename point_type<rtree_value_type>::type, typename point_type < typename std::iterator_traits < QueryRangeIterator >::value_type >::type >::type dist_min; return apply(rtree_first, rtree_last, queries_first, queries_last, strategy, dist_min); } }; }} // namespace detail::closest_feature #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP detail/closest_feature/point_to_range.hpp 0000644 00000017617 15125631657 0014744 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP #include <utility> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace closest_feature { // returns the segment (pair of iterators) that realizes the closest // distance of the point to the range template < typename Point, typename Range, closure_selector Closure, typename Strategy > class point_to_point_range { protected: typedef typename boost::range_iterator<Range const>::type iterator_type; template <typename Distance> static inline void apply(Point const& point, iterator_type first, iterator_type last, Strategy const& strategy, iterator_type& it_min1, iterator_type& it_min2, Distance& dist_min) { BOOST_GEOMETRY_ASSERT( first != last ); Distance const zero = Distance(0); iterator_type it = first; iterator_type prev = it++; if (it == last) { it_min1 = it_min2 = first; dist_min = strategy.apply(point, *first, *first); return; } // start with first segment distance dist_min = strategy.apply(point, *prev, *it); iterator_type prev_min_dist = prev; // check if other segments are closer for (++prev, ++it; it != last; ++prev, ++it) { Distance const dist = strategy.apply(point, *prev, *it); // Stop only if we find exactly zero distance // otherwise it may stop at some very small value and miss the min if (dist == zero) { dist_min = zero; it_min1 = prev; it_min2 = it; return; } else if (dist < dist_min) { dist_min = dist; prev_min_dist = prev; } } it_min1 = it_min2 = prev_min_dist; ++it_min2; } public: typedef typename std::pair<iterator_type, iterator_type> return_type; template <typename Distance> static inline return_type apply(Point const& point, iterator_type first, iterator_type last, Strategy const& strategy, Distance& dist_min) { iterator_type it_min1, it_min2; apply(point, first, last, strategy, it_min1, it_min2, dist_min); return std::make_pair(it_min1, it_min2); } static inline return_type apply(Point const& point, iterator_type first, iterator_type last, Strategy const& strategy) { typename strategy::distance::services::return_type < Strategy, Point, typename boost::range_value<Range>::type >::type dist_min; return apply(point, first, last, strategy, dist_min); } template <typename Distance> static inline return_type apply(Point const& point, Range const& range, Strategy const& strategy, Distance& dist_min) { return apply(point, boost::begin(range), boost::end(range), strategy, dist_min); } static inline return_type apply(Point const& point, Range const& range, Strategy const& strategy) { return apply(point, boost::begin(range), boost::end(range), strategy); } }; // specialization for open ranges template <typename Point, typename Range, typename Strategy> class point_to_point_range<Point, Range, open, Strategy> : point_to_point_range<Point, Range, closed, Strategy> { private: typedef point_to_point_range<Point, Range, closed, Strategy> base_type; typedef typename base_type::iterator_type iterator_type; template <typename Distance> static inline void apply(Point const& point, iterator_type first, iterator_type last, Strategy const& strategy, iterator_type& it_min1, iterator_type& it_min2, Distance& dist_min) { BOOST_GEOMETRY_ASSERT( first != last ); base_type::apply(point, first, last, strategy, it_min1, it_min2, dist_min); iterator_type it_back = --last; Distance const zero = Distance(0); Distance dist = strategy.apply(point, *it_back, *first); if (geometry::math::equals(dist, zero)) { dist_min = zero; it_min1 = it_back; it_min2 = first; } else if (dist < dist_min) { dist_min = dist; it_min1 = it_back; it_min2 = first; } } public: typedef typename std::pair<iterator_type, iterator_type> return_type; template <typename Distance> static inline return_type apply(Point const& point, iterator_type first, iterator_type last, Strategy const& strategy, Distance& dist_min) { iterator_type it_min1, it_min2; apply(point, first, last, strategy, it_min1, it_min2, dist_min); return std::make_pair(it_min1, it_min2); } static inline return_type apply(Point const& point, iterator_type first, iterator_type last, Strategy const& strategy) { typedef typename strategy::distance::services::return_type < Strategy, Point, typename boost::range_value<Range>::type >::type distance_return_type; distance_return_type dist_min; return apply(point, first, last, strategy, dist_min); } template <typename Distance> static inline return_type apply(Point const& point, Range const& range, Strategy const& strategy, Distance& dist_min) { return apply(point, boost::begin(range), boost::end(range), strategy, dist_min); } static inline return_type apply(Point const& point, Range const& range, Strategy const& strategy) { return apply(point, boost::begin(range), boost::end(range), strategy); } }; }} // namespace detail::closest_feature #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP detail/for_each_range.hpp 0000644 00000015552 15125631657 0011464 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP #include <type_traits> #include <utility> #include <boost/concept/requires.hpp> #include <boost/core/addressof.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/type_traits.hpp> #include <boost/geometry/views/box_view.hpp> #include <boost/geometry/views/segment_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace for_each { template <typename Point> struct fe_range_point { template <typename Functor> static inline bool apply(Point& point, Functor&& f) { Point* ptr = boost::addressof(point); return f(std::pair<Point*, Point*>(ptr, ptr + 1)); } }; template <typename Segment> struct fe_range_segment { template <typename Functor> static inline bool apply(Segment& segment, Functor&& f) { return f(segment_view<typename std::remove_const<Segment>::type>(segment)); } }; template <typename Range> struct fe_range_range { template <typename Functor> static inline bool apply(Range& range, Functor&& f) { return f(range); } }; template <typename Polygon> struct fe_range_polygon { template <typename Functor> static inline bool apply(Polygon& polygon, Functor&& f) { return f(exterior_ring(polygon)); // TODO: If some flag says true, also do the inner rings. // for convex hull, it's not necessary } }; template <typename Box> struct fe_range_box { template <typename Functor> static inline bool apply(Box& box, Functor&& f) { return f(box_view<typename std::remove_const<Box>::type>(box)); } }; template <typename Multi, typename SinglePolicy> struct fe_range_multi { template <typename Functor> static inline bool apply(Multi& multi, Functor&& f) { auto const end = boost::end(multi); for (auto it = boost::begin(multi); it != end; ++it) { if (! SinglePolicy::apply(*it, f)) { return false; } } return true; } }; }} // namespace detail::for_each #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct for_each_range { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not or not yet implemented for this Geometry type.", Geometry, Tag); }; template <typename Point> struct for_each_range<Point, point_tag> : detail::for_each::fe_range_point<Point> {}; template <typename Segment> struct for_each_range<Segment, segment_tag> : detail::for_each::fe_range_segment<Segment> {}; template <typename Linestring> struct for_each_range<Linestring, linestring_tag> : detail::for_each::fe_range_range<Linestring> {}; template <typename Ring> struct for_each_range<Ring, ring_tag> : detail::for_each::fe_range_range<Ring> {}; template <typename Polygon> struct for_each_range<Polygon, polygon_tag> : detail::for_each::fe_range_polygon<Polygon> {}; template <typename Box> struct for_each_range<Box, box_tag> : detail::for_each::fe_range_box<Box> {}; template <typename MultiPoint> struct for_each_range<MultiPoint, multi_point_tag> : detail::for_each::fe_range_range<MultiPoint> {}; template <typename Geometry> struct for_each_range<Geometry, multi_linestring_tag> : detail::for_each::fe_range_multi < Geometry, detail::for_each::fe_range_range < util::transcribe_const_t < Geometry, typename boost::range_value<Geometry>::type > > > {}; template <typename Geometry> struct for_each_range<Geometry, multi_polygon_tag> : detail::for_each::fe_range_multi < Geometry, detail::for_each::fe_range_polygon < util::transcribe_const_t < Geometry, typename boost::range_value<Geometry>::type > > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace detail { // Currently for Polygons p is checked only for exterior ring // Should this function be renamed? template <typename Geometry, typename UnaryPredicate> inline bool all_ranges_of(Geometry const& geometry, UnaryPredicate p) { return dispatch::for_each_range<Geometry const>::apply(geometry, p); } // Currently for Polygons p is checked only for exterior ring // Should this function be renamed? template <typename Geometry, typename UnaryPredicate> inline bool any_range_of(Geometry const& geometry, UnaryPredicate p) { return ! dispatch::for_each_range<Geometry const>::apply(geometry, [&](auto&& range) { return ! p(range); }); } // Currently for Polygons p is checked only for exterior ring // Should this function be renamed? template <typename Geometry, typename UnaryPredicate> inline bool none_range_of(Geometry const& geometry, UnaryPredicate p) { return dispatch::for_each_range<Geometry const>::apply(geometry, [&](auto&& range) { return ! p(range); }); } // Currently for Polygons f is called only for exterior ring // Should this function be renamed? template <typename Geometry, typename Functor> inline Functor for_each_range(Geometry const& geometry, Functor f) { dispatch::for_each_range<Geometry const>::apply(geometry, [&](auto&& range) { f(range); // TODO: Implement separate function? return true; }); return f; } } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP detail/not.hpp 0000644 00000003760 15125631657 0007340 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015, 2017. // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { /*! \brief Structure negating the result of specified policy \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Policy \param geometry1 \param_geometry \param geometry2 \param_geometry \return Negation of the result of the policy */ template <typename Policy> struct not_ { template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { return ! Policy::apply(geometry1, geometry2); } template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return ! Policy::apply(geometry1, geometry2, strategy); } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP detail/calculate_null.hpp 0000644 00000002170 15125631657 0011521 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { struct calculate_null { template<typename ReturnType, typename Geometry, typename Strategy> static inline ReturnType apply(Geometry const& , Strategy const&) { return ReturnType(); } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP detail/convert_point_to_point.hpp 0000644 00000004323 15125631657 0013340 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP // Note: extracted from "convert.hpp" to avoid circular references convert/append #include <cstddef> #include <boost/numeric/conversion/cast.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/coordinate_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace conversion { template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount> struct point_to_point { static inline void apply(Source const& source, Destination& destination) { typedef typename coordinate_type<Destination>::type coordinate_type; set<Dimension>(destination, boost::numeric_cast<coordinate_type>(get<Dimension>(source))); point_to_point<Source, Destination, Dimension + 1, DimensionCount>::apply(source, destination); } }; template <typename Source, typename Destination, std::size_t DimensionCount> struct point_to_point<Source, Destination, DimensionCount, DimensionCount> { static inline void apply(Source const& , Destination& ) {} }; template <typename Source, typename Destination> inline void convert_point_to_point(Source const& source, Destination& destination) { point_to_point<Source, Destination, 0, dimension<Destination>::value>::apply(source, destination); } }} // namespace detail::conversion #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP detail/as_range.hpp 0000644 00000005014 15125631657 0010311 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename GeometryTag, typename Geometry, typename Range> struct as_range { static inline Range& get(Geometry& input) { return input; } }; template <typename Geometry, typename Range> struct as_range<polygon_tag, Geometry, Range> { static inline Range& get(Geometry& input) { return exterior_ring(input); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH // Will probably be replaced by the more generic "view_as", therefore in detail namespace detail { /*! \brief Function getting either the range (ring, linestring) itself or the outer ring (polygon) \details Utility to handle polygon's outer ring as a range \ingroup utility */ template <typename Range, typename Geometry> inline Range& as_range(Geometry& input) { return dispatch::as_range < typename tag<Geometry>::type, Geometry, Range >::get(input); } /*! \brief Function getting either the range (ring, linestring) itself or the outer ring (polygon), const version \details Utility to handle polygon's outer ring as a range \ingroup utility */ template <typename Range, typename Geometry> inline Range const& as_range(Geometry const& input) { return dispatch::as_range < typename tag<Geometry>::type, Geometry const, Range const >::get(input); } } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP detail/assign_box_corners.hpp 0000644 00000006412 15125631657 0012424 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP #include <cstddef> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/assign_values.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { // Note: this is moved to namespace detail because the names and parameter orders // are not yet 100% clear. /*! \brief Assign the four points of a 2D box \ingroup assign \note The order is crucial. Most logical is LOWER, UPPER and sub-order LEFT, RIGHT so this is how it is implemented. \tparam Box \tparam_box \tparam Point \tparam_point \param box \param_box \param lower_left point being assigned to lower left coordinates of the box \param lower_right point being assigned to lower right coordinates of the box \param upper_left point being assigned to upper left coordinates of the box \param upper_right point being assigned to upper right coordinates of the box \qbk{ [heading Example] [assign_box_corners] [assign_box_corners_output] } */ template <typename Box, typename Point> inline void assign_box_corners(Box const& box, Point& lower_left, Point& lower_right, Point& upper_left, Point& upper_right) { concepts::check<Box const>(); concepts::check<Point>(); detail::assign::assign_box_2d_corner <min_corner, min_corner>(box, lower_left); detail::assign::assign_box_2d_corner <max_corner, min_corner>(box, lower_right); detail::assign::assign_box_2d_corner <min_corner, max_corner>(box, upper_left); detail::assign::assign_box_2d_corner <max_corner, max_corner>(box, upper_right); } // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif template <bool Reverse, typename Box, typename Range> inline void assign_box_corners_oriented(Box const& box, Range& corners) { if (Reverse) { // make counterclockwise ll,lr,ur,ul assign_box_corners(box, range::at(corners, 0), range::at(corners, 1), range::at(corners, 3), range::at(corners, 2)); } else { // make clockwise ll,ul,ur,lr assign_box_corners(box, range::at(corners, 0), range::at(corners, 3), range::at(corners, 1), range::at(corners, 2)); } } #if defined(_MSC_VER) #pragma warning(pop) #endif } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP detail/course.hpp 0000644 00000002234 15125631657 0010033 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014. // Modifications copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP #include <boost/geometry/algorithms/detail/azimuth.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { /// Calculate course (bearing) between two points. /// /// NOTE: left for convenience and temporary backward compatibility template <typename ReturnType, typename Point1, typename Point2> inline ReturnType course(Point1 const& p1, Point2 const& p2) { return azimuth<ReturnType>(p1, p2); } } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COURSE_HPP detail/convert_indexed_to_indexed.hpp 0000644 00000004370 15125631657 0014120 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP #include <cstddef> #include <boost/numeric/conversion/cast.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/coordinate_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace conversion { template < typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount > struct indexed_to_indexed { static inline void apply(Source const& source, Destination& destination) { typedef typename coordinate_type<Destination>::type coordinate_type; geometry::set<min_corner, Dimension>(destination, boost::numeric_cast<coordinate_type>( geometry::get<min_corner, Dimension>(source))); geometry::set<max_corner, Dimension>(destination, boost::numeric_cast<coordinate_type>( geometry::get<max_corner, Dimension>(source))); indexed_to_indexed < Source, Destination, Dimension + 1, DimensionCount >::apply(source, destination); } }; template < typename Source, typename Destination, std::size_t DimensionCount > struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount> { static inline void apply(Source const& , Destination& ) {} }; }} // namespace detail::conversion #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP detail/is_simple/areal.hpp 0000644 00000011113 15125631657 0011577 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_SIMPLE_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_simple { template <typename Ring, typename CSTag> struct is_simple_ring { static inline bool apply(Ring const& ring) { simplicity_failure_policy policy; return ! boost::empty(ring) && ! detail::is_valid::has_duplicates < Ring, geometry::closure<Ring>::value, CSTag >::apply(ring, policy); } }; template <typename Polygon, typename CSTag> class is_simple_polygon { private: template <typename InteriorRings> static inline bool are_simple_interior_rings(InteriorRings const& interior_rings) { return detail::check_iterator_range < is_simple_ring < typename boost::range_value<InteriorRings>::type, CSTag > >::apply(boost::begin(interior_rings), boost::end(interior_rings)); } public: static inline bool apply(Polygon const& polygon) { return is_simple_ring < typename ring_type<Polygon>::type, CSTag >::apply(exterior_ring(polygon)) && are_simple_interior_rings(geometry::interior_rings(polygon)); } }; }} // namespace detail::is_simple #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A Ring is a Polygon. // A Polygon is always a simple geometric object provided that it is valid. // // Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) template <typename Ring> struct is_simple<Ring, ring_tag> { template <typename Strategy> static inline bool apply(Ring const& ring, Strategy const&) { return detail::is_simple::is_simple_ring < Ring, typename Strategy::cs_tag >::apply(ring); } }; // A Polygon is always a simple geometric object provided that it is valid. // // Reference (for validity of Polygons): OGC 06-103r4 (6.1.11.1) template <typename Polygon> struct is_simple<Polygon, polygon_tag> { template <typename Strategy> static inline bool apply(Polygon const& polygon, Strategy const&) { return detail::is_simple::is_simple_polygon < Polygon, typename Strategy::cs_tag >::apply(polygon); } }; // Not clear what the definition is. // Right now we consider a MultiPolygon as simple if it is valid. // // Reference (for validity of MultiPolygons): OGC 06-103r4 (6.1.14) template <typename MultiPolygon> struct is_simple<MultiPolygon, multi_polygon_tag> { template <typename Strategy> static inline bool apply(MultiPolygon const& multipolygon, Strategy const&) { return detail::check_iterator_range < detail::is_simple::is_simple_polygon < typename boost::range_value<MultiPolygon>::type, typename Strategy::cs_tag >, true // allow empty multi-polygon >::apply(boost::begin(multipolygon), boost::end(multipolygon)); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_AREAL_HPP detail/is_simple/linear.hpp 0000644 00000027374 15125631657 0012005 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_SIMPLE_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP #include <algorithm> #include <deque> #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/coordinate_type.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/policies/predicate_based_interrupt_policy.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> #include <boost/geometry/policies/robustness/segment_ratio.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/algorithms/detail/signed_size_type.hpp> #include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp> #include <boost/geometry/algorithms/detail/equals/point_point.hpp> #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/turn_info.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp> #include <boost/geometry/algorithms/detail/is_simple/debug_print_boundary_points.hpp> #include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp> #include <boost/geometry/algorithms/detail/is_valid/debug_print_turns.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> #include <boost/geometry/strategies/intersection.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_simple { template <typename Turn> inline bool check_segment_indices(Turn const& turn, signed_size_type last_index) { return (turn.operations[0].seg_id.segment_index == 0 && turn.operations[1].seg_id.segment_index == last_index) || (turn.operations[0].seg_id.segment_index == 0 && turn.operations[1].seg_id.segment_index == last_index); } template < typename Geometry, typename EqPPStrategy, typename Tag = typename tag<Geometry>::type > class is_acceptable_turn : not_implemented<Geometry> {}; template <typename Linestring, typename EqPPStrategy> class is_acceptable_turn<Linestring, EqPPStrategy, linestring_tag> { public: is_acceptable_turn(Linestring const& linestring) : m_linestring(linestring) , m_is_closed(geometry::detail::equals::equals_point_point(range::front(linestring), range::back(linestring), EqPPStrategy())) {} template <typename Turn> inline bool apply(Turn const& turn) const { BOOST_GEOMETRY_ASSERT(boost::size(m_linestring) > 1); return m_is_closed && turn.method == overlay::method_none && check_segment_indices(turn, boost::size(m_linestring) - 2) && turn.operations[0].fraction.is_zero(); } private: Linestring const& m_linestring; bool const m_is_closed; }; template <typename MultiLinestring, typename EqPPStrategy> class is_acceptable_turn<MultiLinestring, EqPPStrategy, multi_linestring_tag> { private: template <typename Point1, typename Point2> static inline bool equals_point_point(Point1 const& point1, Point2 const& point2) { return geometry::detail::equals::equals_point_point(point1, point2, EqPPStrategy()); } template <typename Point, typename Linestring> static inline bool is_boundary_point_of(Point const& point, Linestring const& linestring) { BOOST_GEOMETRY_ASSERT(boost::size(linestring) > 1); return !equals_point_point(range::front(linestring), range::back(linestring)) && (equals_point_point(point, range::front(linestring)) || equals_point_point(point, range::back(linestring))); } template <typename Turn, typename Linestring> static inline bool is_closing_point_of(Turn const& turn, Linestring const& linestring) { BOOST_GEOMETRY_ASSERT(boost::size(linestring) > 1); return turn.method == overlay::method_none && check_segment_indices(turn, boost::size(linestring) - 2) && equals_point_point(range::front(linestring), range::back(linestring)) && turn.operations[0].fraction.is_zero(); ; } template <typename Linestring1, typename Linestring2> static inline bool have_same_boundary_points(Linestring1 const& ls1, Linestring2 const& ls2) { return equals_point_point(range::front(ls1), range::front(ls2)) ? equals_point_point(range::back(ls1), range::back(ls2)) : (equals_point_point(range::front(ls1), range::back(ls2)) && equals_point_point(range::back(ls1), range::front(ls2))) ; } public: is_acceptable_turn(MultiLinestring const& multilinestring) : m_multilinestring(multilinestring) {} template <typename Turn> inline bool apply(Turn const& turn) const { typedef typename boost::range_value<MultiLinestring>::type linestring_type; linestring_type const& ls1 = range::at(m_multilinestring, turn.operations[0].seg_id.multi_index); linestring_type const& ls2 = range::at(m_multilinestring, turn.operations[1].seg_id.multi_index); if (turn.operations[0].seg_id.multi_index == turn.operations[1].seg_id.multi_index) { return is_closing_point_of(turn, ls1); } return is_boundary_point_of(turn.point, ls1) && is_boundary_point_of(turn.point, ls2) && ( boost::size(ls1) != 2 || boost::size(ls2) != 2 || ! have_same_boundary_points(ls1, ls2) ); } private: MultiLinestring const& m_multilinestring; }; template <typename Linear, typename Strategy> inline bool has_self_intersections(Linear const& linear, Strategy const& strategy) { typedef typename point_type<Linear>::type point_type; // compute self turns typedef detail::overlay::turn_info<point_type> turn_info; std::deque<turn_info> turns; typedef detail::overlay::get_turn_info < detail::disjoint::assign_disjoint_policy > turn_policy; typedef is_acceptable_turn < Linear, typename Strategy::equals_point_point_strategy_type > is_acceptable_turn_type; is_acceptable_turn_type predicate(linear); detail::overlay::predicate_based_interrupt_policy < is_acceptable_turn_type > interrupt_policy(predicate); // TODO: skip_adjacent should be set to false detail::self_get_turn_points::get_turns < false, turn_policy >::apply(linear, strategy, detail::no_rescale_policy(), turns, interrupt_policy, 0, true); detail::is_valid::debug_print_turns(turns.begin(), turns.end()); debug_print_boundary_points(linear); return interrupt_policy.has_intersections; } template <typename Linestring, bool CheckSelfIntersections = true> struct is_simple_linestring { template <typename Strategy> static inline bool apply(Linestring const& linestring, Strategy const& strategy) { simplicity_failure_policy policy; return ! boost::empty(linestring) && ! detail::is_valid::has_duplicates < Linestring, closed, typename Strategy::cs_tag >::apply(linestring, policy) && ! detail::is_valid::has_spikes < Linestring, closed >::apply(linestring, policy, strategy.get_side_strategy()); } }; template <typename Linestring> struct is_simple_linestring<Linestring, true> { template <typename Strategy> static inline bool apply(Linestring const& linestring, Strategy const& strategy) { return is_simple_linestring < Linestring, false >::apply(linestring, strategy) && ! has_self_intersections(linestring, strategy); } }; template <typename MultiLinestring> struct is_simple_multilinestring { private: template <typename Strategy> struct per_linestring { per_linestring(Strategy const& strategy) : m_strategy(strategy) {} template <typename Linestring> inline bool apply(Linestring const& linestring) const { return detail::is_simple::is_simple_linestring < Linestring, false // do not compute self-intersections >::apply(linestring, m_strategy); } Strategy const& m_strategy; }; public: template <typename Strategy> static inline bool apply(MultiLinestring const& multilinestring, Strategy const& strategy) { typedef per_linestring<Strategy> per_ls; // check each of the linestrings for simplicity // but do not compute self-intersections yet; these will be // computed for the entire multilinestring if ( ! detail::check_iterator_range < per_ls, // do not compute self-intersections true // allow empty multilinestring >::apply(boost::begin(multilinestring), boost::end(multilinestring), per_ls(strategy)) ) { return false; } return ! has_self_intersections(multilinestring, strategy); } }; }} // namespace detail::is_simple #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A linestring is a curve. // A curve is simple if it does not pass through the same point twice, // with the possible exception of its two endpoints // // Reference: OGC 06-103r4 (6.1.6.1) template <typename Linestring> struct is_simple<Linestring, linestring_tag> : detail::is_simple::is_simple_linestring<Linestring> {}; // A MultiLinestring is a MultiCurve // A MultiCurve is simple if all of its elements are simple and the // only intersections between any two elements occur at Points that // are on the boundaries of both elements. // // Reference: OGC 06-103r4 (6.1.8.1; Fig. 9) template <typename MultiLinestring> struct is_simple<MultiLinestring, multi_linestring_tag> : detail::is_simple::is_simple_multilinestring<MultiLinestring> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP detail/is_simple/multipoint.hpp 0000644 00000004625 15125631657 0012731 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_SIMPLE_MULTIPOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP #include <algorithm> #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/algorithms/detail/is_valid/has_duplicates.hpp> #include <boost/geometry/algorithms/detail/is_simple/failure_policy.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_simple { template <typename MultiPoint> struct is_simple_multipoint { template <typename Strategy> static inline bool apply(MultiPoint const& multipoint, Strategy const&) { typedef typename Strategy::cs_tag cs_tag; typedef geometry::less < typename point_type<MultiPoint>::type, -1, cs_tag > less_type; if (boost::empty(multipoint)) { return true; } MultiPoint mp(multipoint); std::sort(boost::begin(mp), boost::end(mp), less_type()); simplicity_failure_policy policy; return !detail::is_valid::has_duplicates < MultiPoint, closed, cs_tag >::apply(mp, policy); } }; }} // namespace detail::is_simple #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A MultiPoint is simple if no two Points in the MultiPoint are equal // (have identical coordinate values in X and Y) // // Reference: OGC 06-103r4 (6.1.5) template <typename MultiPoint> struct is_simple<MultiPoint, multi_point_tag> : detail::is_simple::is_simple_multipoint<MultiPoint> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_MULTIPOINT_HPP detail/is_simple/implementation.hpp 0000644 00000001402 15125631657 0013540 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP #include <boost/geometry/algorithms/detail/is_simple/always_simple.hpp> #include <boost/geometry/algorithms/detail/is_simple/areal.hpp> #include <boost/geometry/algorithms/detail/is_simple/linear.hpp> #include <boost/geometry/algorithms/detail/is_simple/multipoint.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_IMPLEMENTATION_HPP detail/is_simple/debug_print_boundary_points.hpp 0000644 00000006617 15125631657 0016331 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP #ifdef BOOST_GEOMETRY_TEST_DEBUG #include <algorithm> #include <iostream> #include <vector> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/io/dsv/write.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/algorithms/equals.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #endif // BOOST_GEOMETRY_TEST_DEBUG namespace boost { namespace geometry { namespace detail { namespace is_simple { #ifdef BOOST_GEOMETRY_TEST_DEBUG template <typename Linear, typename Tag = typename tag<Linear>::type> struct debug_boundary_points_printer : not_implemented<Linear> {}; template <typename Linestring> struct debug_boundary_points_printer<Linestring, linestring_tag> { static inline void apply(Linestring const& linestring) { std::cout << "boundary points: "; std::cout << " " << geometry::dsv(range::front(linestring)); std::cout << " " << geometry::dsv(range::back(linestring)); std::cout << std::endl << std::endl; } }; template <typename MultiLinestring> struct debug_boundary_points_printer<MultiLinestring, multi_linestring_tag> { static inline void apply(MultiLinestring const& multilinestring) { typedef typename point_type<MultiLinestring>::type point_type; typedef std::vector<point_type> point_vector; point_vector boundary_points; for (typename boost::range_iterator<MultiLinestring const>::type it = boost::begin(multilinestring); it != boost::end(multilinestring); ++it) { if ( boost::size(*it) > 1 && !geometry::equals(range::front(*it), range::back(*it)) ) { boundary_points.push_back( range::front(*it) ); boundary_points.push_back( range::back(*it) ); } } std::sort(boundary_points.begin(), boundary_points.end(), geometry::less<point_type>()); std::cout << "boundary points: "; for (typename point_vector::const_iterator pit = boundary_points.begin(); pit != boundary_points.end(); ++pit) { std::cout << " " << geometry::dsv(*pit); } std::cout << std::endl << std::endl; } }; template <typename Linear> inline void debug_print_boundary_points(Linear const& linear) { debug_boundary_points_printer<Linear>::apply(linear); } #else template <typename Linear> inline void debug_print_boundary_points(Linear const&) { } #endif // BOOST_GEOMETRY_TEST_DEBUG }} // namespace detail::is_simple }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_DEBUG_PRINT_BOUNDARY_POINTS_HPP detail/is_simple/interface.hpp 0000644 00000007451 15125631657 0012465 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_SIMPLE_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/intersection.hpp> namespace boost { namespace geometry { namespace resolve_strategy { struct is_simple { template <typename Geometry, typename Strategy> static inline bool apply(Geometry const& geometry, Strategy const& strategy) { return dispatch::is_simple<Geometry>::apply(geometry, strategy); } template <typename Geometry> static inline bool apply(Geometry const& geometry, default_strategy) { // NOTE: Currently the strategy is only used for Linear geometries typedef typename strategy::intersection::services::default_strategy < typename cs_tag<Geometry>::type >::type strategy_type; return dispatch::is_simple<Geometry>::apply(geometry, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct is_simple { template <typename Strategy> static inline bool apply(Geometry const& geometry, Strategy const& strategy) { concepts::check<Geometry const>(); return resolve_strategy::is_simple::apply(geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_simple<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor : boost::static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry> bool operator()(Geometry const& geometry) const { return is_simple<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant /*! \brief \brief_check{is simple} \ingroup is_simple \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Is_simple} \param geometry \param_geometry \param strategy \param_strategy{is_simple} \return \return_check{is simple} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/is_simple.qbk]} */ template <typename Geometry, typename Strategy> inline bool is_simple(Geometry const& geometry, Strategy const& strategy) { return resolve_variant::is_simple<Geometry>::apply(geometry, strategy); } /*! \brief \brief_check{is simple} \ingroup is_simple \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_check{is simple} \qbk{[include reference/algorithms/is_simple.qbk]} */ template <typename Geometry> inline bool is_simple(Geometry const& geometry) { return resolve_variant::is_simple<Geometry>::apply(geometry, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_INTERFACE_HPP detail/is_simple/failure_policy.hpp 0000644 00000002361 15125631657 0013526 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP #include <boost/geometry/algorithms/validity_failure_type.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_simple { struct simplicity_failure_policy { template <validity_failure_type Failure> static inline bool apply() { return Failure == no_failure; } template <validity_failure_type Failure, typename Data> static inline bool apply(Data const&) { return apply<Failure>(); } template <validity_failure_type Failure, typename Data1, typename Data2> static inline bool apply(Data1 const&, Data2 const&) { return apply<Failure>(); } }; }} // namespace detail::is_simple #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_FAILURE_POLICY_HPP detail/is_simple/always_simple.hpp 0000644 00000003626 15125631657 0013376 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/dispatch/is_simple.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_simple { template <typename Geometry> struct always_simple { template <typename Strategy> static inline bool apply(Geometry const&, Strategy const&) { return true; } }; }} // namespace detail::is_simple #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // A point is always simple template <typename Point> struct is_simple<Point, point_tag> : detail::is_simple::always_simple<Point> {}; // A valid segment is always simple. // A segment is a curve. // A curve is simple if it does not pass through the same point twice, // with the possible exception of its two endpoints // // Reference: OGC 06-103r4 (6.1.6.1) template <typename Segment> struct is_simple<Segment, segment_tag> : detail::is_simple::always_simple<Segment> {}; // A valid box is always simple // A box is a Polygon, and it satisfies the conditions for Polygon validity. // // Reference (for polygon validity): OGC 06-103r4 (6.1.11.1) template <typename Box> struct is_simple<Box, box_tag> : detail::is_simple::always_simple<Box> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_ALWAYS_SIMPLE_HPP detail/touches/implementation.hpp 0000644 00000032616 15125631657 0013241 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2020. // Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP #include <type_traits> #include <boost/geometry/algorithms/detail/for_each_range.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> #include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp> #include <boost/geometry/algorithms/detail/sub_range.hpp> #include <boost/geometry/algorithms/detail/relate/relate_impl.hpp> #include <boost/geometry/algorithms/detail/touches/interface.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/intersects.hpp> #include <boost/geometry/algorithms/num_geometries.hpp> #include <boost/geometry/algorithms/relate.hpp> #include <boost/geometry/policies/robustness/no_rescale_policy.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace touches { // Box/Box template < std::size_t Dimension, std::size_t DimensionCount > struct box_box_loop { template <typename Box1, typename Box2> static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch) { typedef typename coordinate_type<Box1>::type coordinate_type1; typedef typename coordinate_type<Box2>::type coordinate_type2; coordinate_type1 const& min1 = get<min_corner, Dimension>(b1); coordinate_type1 const& max1 = get<max_corner, Dimension>(b1); coordinate_type2 const& min2 = get<min_corner, Dimension>(b2); coordinate_type2 const& max2 = get<max_corner, Dimension>(b2); // TODO assert or exception? //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2); if (max1 < min2 || max2 < min1) { return false; } if (max1 == min2 || max2 == min1) { touch = true; } return box_box_loop < Dimension + 1, DimensionCount >::apply(b1, b2, touch); } }; template < std::size_t DimensionCount > struct box_box_loop<DimensionCount, DimensionCount> { template <typename Box1, typename Box2> static inline bool apply(Box1 const& , Box2 const&, bool &) { return true; } }; struct box_box { template <typename Box1, typename Box2, typename Strategy> static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/) { BOOST_STATIC_ASSERT((std::is_same < typename geometry::coordinate_system<Box1>::type, typename geometry::coordinate_system<Box2>::type >::value )); assert_dimension_equal<Box1, Box2>(); bool touches = false; bool ok = box_box_loop < 0, dimension<Box1>::type::value >::apply(b1, b2, touches); return ok && touches; } }; // Areal/Areal struct areal_interrupt_policy { static bool const enabled = true; bool found_touch; bool found_not_touch; // dummy variable required by self_get_turn_points::get_turns static bool const has_intersections = false; inline bool result() { return found_touch && !found_not_touch; } inline areal_interrupt_policy() : found_touch(false), found_not_touch(false) {} template <typename Range> inline bool apply(Range const& range) { // if already rejected (temp workaround?) if ( found_not_touch ) return true; typedef typename boost::range_iterator<Range const>::type iterator; for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it ) { if ( it->has(overlay::operation_intersection) ) { found_not_touch = true; return true; } switch(it->method) { case overlay::method_crosses: found_not_touch = true; return true; case overlay::method_equal: // Segment spatially equal means: at the right side // the polygon internally overlaps. So return false. found_not_touch = true; return true; case overlay::method_touch: case overlay::method_touch_interior: case overlay::method_collinear: if ( ok_for_touch(*it) ) { found_touch = true; } else { found_not_touch = true; return true; } break; case overlay::method_start : case overlay::method_none : case overlay::method_disjoint : case overlay::method_error : break; } } return false; } template <typename Turn> inline bool ok_for_touch(Turn const& turn) { return turn.both(overlay::operation_union) || turn.both(overlay::operation_blocked) || turn.combination(overlay::operation_union, overlay::operation_blocked) ; } }; template <typename Geometry1, typename Geometry2, typename Strategy> inline bool point_on_border_within(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { typename geometry::point_type<Geometry1>::type pt; return geometry::point_on_border(pt, geometry1) && geometry::within(pt, geometry2, strategy); } template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy> inline bool rings_containing(FirstGeometry const& geometry1, SecondGeometry const& geometry2, IntersectionStrategy const& strategy) { // TODO: This will be removed when IntersectionStrategy is replaced with // UmbrellaStrategy auto const point_in_ring_strategy = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>(); return geometry::detail::any_range_of(geometry2, [&](auto const& range) { return point_on_border_within(range, geometry1, point_in_ring_strategy); }); } template <typename Geometry1, typename Geometry2> struct areal_areal { template <typename IntersectionStrategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, IntersectionStrategy const& strategy) { typedef typename geometry::point_type<Geometry1>::type point_type; typedef detail::overlay::turn_info<point_type> turn_info; std::deque<turn_info> turns; detail::touches::areal_interrupt_policy policy; boost::geometry::get_turns < detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, detail::overlay::assign_null_policy >(geometry1, geometry2, strategy, detail::no_rescale_policy(), turns, policy); return policy.result() && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy) && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy); } }; // P/* struct use_point_in_geometry { template <typename Point, typename Geometry, typename Strategy> static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy) { return detail::within::point_in_geometry(point, geometry, strategy) == 0; } }; }} #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // P/P template <typename Geometry1, typename Geometry2> struct touches<Geometry1, Geometry2, point_tag, point_tag, pointlike_tag, pointlike_tag, false> { template <typename Strategy> static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&) { return false; } }; template <typename Geometry1, typename Geometry2> struct touches<Geometry1, Geometry2, point_tag, multi_point_tag, pointlike_tag, pointlike_tag, false> { template <typename Strategy> static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&) { return false; } }; template <typename Geometry1, typename Geometry2> struct touches<Geometry1, Geometry2, multi_point_tag, multi_point_tag, pointlike_tag, pointlike_tag, false> { template <typename Strategy> static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&) { return false; } }; // P/L P/A template <typename Point, typename Geometry, typename Tag2, typename CastedTag2> struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false> : detail::touches::use_point_in_geometry {}; template <typename MultiPoint, typename MultiGeometry, typename Tag2, typename CastedTag2> struct touches<MultiPoint, MultiGeometry, multi_point_tag, Tag2, pointlike_tag, CastedTag2, false> : detail::relate::relate_impl < detail::de9im::static_mask_touches_type, MultiPoint, MultiGeometry > {}; // L/P A/P template <typename Geometry, typename MultiPoint, typename Tag1, typename CastedTag1> struct touches<Geometry, MultiPoint, Tag1, multi_point_tag, CastedTag1, pointlike_tag, false> : detail::relate::relate_impl < detail::de9im::static_mask_touches_type, Geometry, MultiPoint > {}; // Box/Box template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2> struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false> : detail::touches::box_box {}; template <typename Box1, typename Box2> struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false> : detail::touches::box_box {}; // L/L template <typename Linear1, typename Linear2, typename Tag1, typename Tag2> struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false> : detail::relate::relate_impl < detail::de9im::static_mask_touches_type, Linear1, Linear2 > {}; // L/A template <typename Linear, typename Areal, typename Tag1, typename Tag2> struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false> : detail::relate::relate_impl < detail::de9im::static_mask_touches_type, Linear, Areal > {}; // A/L template <typename Linear, typename Areal, typename Tag1, typename Tag2> struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false> : detail::relate::relate_impl < detail::de9im::static_mask_touches_type, Areal, Linear > {}; // A/A template <typename Areal1, typename Areal2, typename Tag1, typename Tag2> struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false> : detail::relate::relate_impl < detail::de9im::static_mask_touches_type, Areal1, Areal2 > {}; template <typename Areal1, typename Areal2> struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false> : detail::touches::areal_areal<Areal1, Areal2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct self_touches { static bool apply(Geometry const& geometry) { concepts::check<Geometry const>(); typedef typename strategy::relate::services::default_strategy < Geometry, Geometry >::type strategy_type; typedef typename geometry::point_type<Geometry>::type point_type; typedef detail::overlay::turn_info<point_type> turn_info; typedef detail::overlay::get_turn_info < detail::overlay::assign_null_policy > policy_type; std::deque<turn_info> turns; detail::touches::areal_interrupt_policy policy; strategy_type strategy; // TODO: skip_adjacent should be set to false detail::self_get_turn_points::get_turns < false, policy_type >::apply(geometry, strategy, detail::no_rescale_policy(), turns, policy, 0, true); return policy.result(); } }; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP detail/touches/interface.hpp 0000644 00000023637 15125631657 0012157 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013, 2014, 2015, 2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP #include <deque> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/relate.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { // TODO: Since CastedTags are used is Reverse needed? template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type, typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type, typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type, bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value > struct touches : not_implemented<Tag1, Tag2> {}; // If reversal is needed, perform it template < typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, typename CastedTag1, typename CastedTag2 > struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true> : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false> { template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { return touches<Geometry2, Geometry1>::apply(g2, g1, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct touches { template <typename Geometry1, typename Geometry2, typename Strategy> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return dispatch::touches < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } template <typename Geometry1, typename Geometry2> static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return dispatch::touches < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct touches { template <typename Strategy> static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); return resolve_strategy::touches::apply(geometry1, geometry2, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry2 const& m_geometry2; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Strategy const& strategy) : m_geometry2(geometry2) , m_strategy(strategy) {} template <typename Geometry1> bool operator()(Geometry1 const& geometry1) const { return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Geometry1 const& m_geometry1; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Strategy const& strategy) : m_geometry1(geometry1) , m_strategy(strategy) {} template <typename Geometry2> bool operator()(Geometry2 const& geometry2) const { return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(Geometry1 const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Strategy> struct visitor: boost::static_visitor<bool> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> bool operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy); } }; template <typename Strategy> static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2); } }; template <typename Geometry> struct self_touches; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<bool> { template <typename Geometry> bool operator()(Geometry const& geometry) const { return self_touches<Geometry>::apply(geometry); } }; static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) { return boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief \brief_check{has at least one touching point (self-tangency)} \note This function can be called for one geometry (self-tangency) and also for two geometries (touch) \ingroup touches \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_check{is self-touching} \qbk{distinguish,one geometry} \qbk{[def __one_parameter__]} \qbk{[include reference/algorithms/touches.qbk]} \qbk{ [heading Examples] [touches_one_geometry] [touches_one_geometry_output] } */ template <typename Geometry> inline bool touches(Geometry const& geometry) { return resolve_variant::self_touches<Geometry>::apply(geometry); } /*! \brief \brief_check2{have at least one touching point (tangent - non overlapping)} \ingroup touches \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry \param geometry2 \param_geometry \return \return_check2{touch each other} \qbk{distinguish,two geometries} \qbk{[include reference/algorithms/touches.qbk]} \qbk{ [heading Examples] [touches_two_geometries] [touches_two_geometries_output] } */ template <typename Geometry1, typename Geometry2> inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2) { return resolve_variant::touches < Geometry1, Geometry2 >::apply(geometry1, geometry2, default_strategy()); } /*! \brief \brief_check2{have at least one touching point (tangent - non overlapping)} \ingroup touches \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy \tparam_strategy{Touches} \param geometry1 \param_geometry \param geometry2 \param_geometry \param strategy \param_strategy{touches} \return \return_check2{touch each other} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/touches.qbk]} */ template <typename Geometry1, typename Geometry2, typename Strategy> inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return resolve_variant::touches < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP detail/direction_code.hpp 0000644 00000022037 15125631657 0011510 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2020 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP #include <type_traits> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/arithmetic/infinite_line_functions.hpp> #include <boost/geometry/algorithms/detail/make/make.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template <typename CSTag> struct direction_code_impl { BOOST_GEOMETRY_STATIC_ASSERT_FALSE( "Not implemented for this coordinate system.", CSTag); }; template <> struct direction_code_impl<cartesian_tag> { template <typename Point1, typename Point2> static inline int apply(Point1 const& segment_a, Point1 const& segment_b, Point2 const& point) { typedef typename geometry::select_coordinate_type < Point1, Point2 >::type calc_t; typedef model::infinite_line<calc_t> line_type; // Situation and construction of perpendicular line // // P1 a--------------->b P2 // | // | // v // // P1 is located right of the (directional) perpendicular line // and therefore gets a negative side_value, and returns -1. // P2 is to the left of the perpendicular line and returns 1. // If the specified point is located on top of b, it returns 0. line_type const line = detail::make::make_perpendicular_line<calc_t>(segment_a, segment_b, segment_b); if (arithmetic::is_degenerate(line)) { return 0; } calc_t const sv = arithmetic::side_value(line, point); return sv == 0 ? 0 : sv > 0 ? 1 : -1; } }; template <> struct direction_code_impl<spherical_equatorial_tag> { template <typename Point1, typename Point2> static inline int apply(Point1 const& segment_a, Point1 const& segment_b, Point2 const& p) { typedef typename coordinate_type<Point1>::type coord1_t; typedef typename coordinate_type<Point2>::type coord2_t; typedef typename cs_angular_units<Point1>::type units_t; typedef typename cs_angular_units<Point2>::type units2_t; BOOST_GEOMETRY_STATIC_ASSERT( (std::is_same<units_t, units2_t>::value), "Not implemented for different units.", units_t, units2_t); typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t; typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1; typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2; static coord1_t const pi_half1 = constants1::max_latitude(); static coord2_t const pi_half2 = constants2::max_latitude(); static calc_t const c0 = 0; coord1_t const a0 = geometry::get<0>(segment_a); coord1_t const a1 = geometry::get<1>(segment_a); coord1_t const b0 = geometry::get<0>(segment_b); coord1_t const b1 = geometry::get<1>(segment_b); coord2_t const p0 = geometry::get<0>(p); coord2_t const p1 = geometry::get<1>(p); if ( (math::equals(b0, a0) && math::equals(b1, a1)) || (math::equals(b0, p0) && math::equals(b1, p1)) ) { return 0; } bool const is_a_pole = math::equals(pi_half1, math::abs(a1)); bool const is_b_pole = math::equals(pi_half1, math::abs(b1)); bool const is_p_pole = math::equals(pi_half2, math::abs(p1)); if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1)) || (is_p_pole && math::sign(b1) == math::sign(p1))) ) { return 0; } // NOTE: as opposed to the implementation for cartesian CS // here point b is the origin calc_t const dlon1 = math::longitude_distance_signed<units_t, calc_t>(b0, a0); calc_t const dlon2 = math::longitude_distance_signed<units_t, calc_t>(b0, p0); bool is_antilon1 = false, is_antilon2 = false; calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1); calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2); calc_t mx = is_a_pole || is_b_pole || is_p_pole ? c0 : (std::min)(is_antilon1 ? c0 : math::abs(dlon1), is_antilon2 ? c0 : math::abs(dlon2)); calc_t my = (std::min)(math::abs(dlat1), math::abs(dlat2)); int s1 = 0, s2 = 0; if (mx >= my) { s1 = dlon1 > 0 ? 1 : -1; s2 = dlon2 > 0 ? 1 : -1; } else { s1 = dlat1 > 0 ? 1 : -1; s2 = dlat2 > 0 ? 1 : -1; } return s1 == s2 ? -1 : 1; } template <typename Units, typename T> static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon) { typedef math::detail::constants_on_spheroid<T, Units> constants; static T const pi = constants::half_period(); static T const c0 = 0; T res = lat2 - lat1; is_antilon = math::equals(math::abs(lon_ds), pi); if (is_antilon) { res = lat2 + lat1; if (res >= c0) res = pi - res; else res = -pi - res; } return res; } }; template <> struct direction_code_impl<spherical_polar_tag> { template <typename Point1, typename Point2> static inline int apply(Point1 segment_a, Point1 segment_b, Point2 p) { typedef math::detail::constants_on_spheroid < typename coordinate_type<Point1>::type, typename cs_angular_units<Point1>::type > constants1; typedef math::detail::constants_on_spheroid < typename coordinate_type<Point2>::type, typename cs_angular_units<Point2>::type > constants2; geometry::set<1>(segment_a, constants1::max_latitude() - geometry::get<1>(segment_a)); geometry::set<1>(segment_b, constants1::max_latitude() - geometry::get<1>(segment_b)); geometry::set<1>(p, constants2::max_latitude() - geometry::get<1>(p)); return direction_code_impl < spherical_equatorial_tag >::apply(segment_a, segment_b, p); } }; // if spherical_tag is passed then pick cs_tag based on Point1 type // with spherical_equatorial_tag as the default template <> struct direction_code_impl<spherical_tag> { template <typename Point1, typename Point2> static inline int apply(Point1 segment_a, Point1 segment_b, Point2 p) { return direction_code_impl < std::conditional_t < std::is_same < typename geometry::cs_tag<Point1>::type, spherical_polar_tag >::value, spherical_polar_tag, spherical_equatorial_tag > >::apply(segment_a, segment_b, p); } }; template <> struct direction_code_impl<geographic_tag> : direction_code_impl<spherical_equatorial_tag> {}; // Gives sense of direction for point p, collinear w.r.t. segment (a,b) // Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a // Returns 1 if p goes forward, so extends (a,b) // Returns 0 if p is equal with b, or if (a,b) is degenerate // Note that it does not do any collinearity test, that should be done before template <typename CSTag, typename Point1, typename Point2> inline int direction_code(Point1 const& segment_a, Point1 const& segment_b, Point2 const& p) { return direction_code_impl<CSTag>::apply(segment_a, segment_b, p); } } // namespace detail #endif //DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP envelope.hpp 0000644 00000001775 15125631657 0007117 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015. // Modifications copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP #define BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP #include <boost/geometry/algorithms/detail/envelope/interface.hpp> #include <boost/geometry/algorithms/detail/envelope/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_ENVELOPE_HPP reverse.hpp 0000644 00000010714 15125631657 0006746 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_REVERSE_HPP #define BOOST_GEOMETRY_ALGORITHMS_REVERSE_HPP #include <algorithm> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/multi_modify.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace reverse { struct range_reverse { template <typename Range> static inline void apply(Range& range) { std::reverse(boost::begin(range), boost::end(range)); } }; struct polygon_reverse: private range_reverse { template <typename Polygon> static inline void apply(Polygon& polygon) { range_reverse::apply(exterior_ring(polygon)); typename interior_return_type<Polygon>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon>::type it = boost::begin(rings); it != boost::end(rings); ++it) { range_reverse::apply(*it); } } }; }} // namespace detail::reverse #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct reverse { static inline void apply(Geometry&) {} }; template <typename Ring> struct reverse<Ring, ring_tag> : detail::reverse::range_reverse {}; template <typename LineString> struct reverse<LineString, linestring_tag> : detail::reverse::range_reverse {}; template <typename Polygon> struct reverse<Polygon, polygon_tag> : detail::reverse::polygon_reverse {}; template <typename Geometry> struct reverse<Geometry, multi_linestring_tag> : detail::multi_modify < Geometry, detail::reverse::range_reverse > {}; template <typename Geometry> struct reverse<Geometry, multi_polygon_tag> : detail::multi_modify < Geometry, detail::reverse::polygon_reverse > {}; } // namespace dispatch #endif namespace resolve_variant { template <typename Geometry> struct reverse { static void apply(Geometry& geometry) { concepts::check<Geometry>(); dispatch::reverse<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct reverse<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<void> { template <typename Geometry> void operator()(Geometry& geometry) const { reverse<Geometry>::apply(geometry); } }; static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) { boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief Reverses the points within a geometry \details Generic function to reverse a geometry. It resembles the std::reverse functionality, but it takes the geometry type into account. Only for a ring or for a linestring it is the same as the std::reverse. \ingroup reverse \tparam Geometry \tparam_geometry \param geometry \param_geometry which will be reversed \qbk{[include reference/algorithms/reverse.qbk]} */ template <typename Geometry> inline void reverse(Geometry& geometry) { resolve_variant::reverse<Geometry>::apply(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_REVERSE_HPP area.hpp 0000644 00000026165 15125631657 0006212 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2017-2020. // Modifications copyright (c) 2017-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_AREA_HPP #define BOOST_GEOMETRY_ALGORITHMS_AREA_HPP #include <boost/concept_check.hpp> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/detail/calculate_null.hpp> #include <boost/geometry/algorithms/detail/calculate_sum.hpp> // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/algorithms/detail/multi_sum.hpp> #include <boost/geometry/algorithms/area_result.hpp> #include <boost/geometry/algorithms/default_area_result.hpp> #include <boost/geometry/strategies/area/services.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategy/area.hpp> #include <boost/geometry/strategies/concepts/area_concept.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/order_as_direction.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/views/reversible_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace area { struct box_area { template <typename Box, typename Strategy> static inline typename coordinate_type<Box>::type apply(Box const& box, Strategy const&) { // Currently only works for 2D Cartesian boxes assert_dimension<Box, 2>(); return (get<max_corner, 0>(box) - get<min_corner, 0>(box)) * (get<max_corner, 1>(box) - get<min_corner, 1>(box)); } }; template < iterate_direction Direction, closure_selector Closure > struct ring_area { template <typename Ring, typename Strategies> static inline typename area_result<Ring, Strategies>::type apply(Ring const& ring, Strategies const& strategies) { using strategy_type = decltype(strategies.area(ring)); BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy<Ring, strategy_type>) ); assert_dimension<Ring, 2>(); // Ignore warning (because using static method sometimes) on strategy boost::ignore_unused(strategies); // An open ring has at least three points, // A closed ring has at least four points, // if not, there is no (zero) area if (boost::size(ring) < core_detail::closure::minimum_ring_size<Closure>::value) { return typename area_result<Ring, Strategies>::type(); } typedef typename reversible_view<Ring const, Direction>::type rview_type; typedef typename closeable_view < rview_type const, Closure >::type view_type; typedef typename boost::range_iterator<view_type const>::type iterator_type; rview_type rview(ring); view_type view(rview); iterator_type it = boost::begin(view); iterator_type end = boost::end(view); strategy_type strategy = strategies.area(ring); typename strategy_type::template state<Ring> state; for (iterator_type previous = it++; it != end; ++previous, ++it) { strategy.apply(*previous, *it, state); } return strategy.result(state); } }; }} // namespace detail::area #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct area : detail::calculate_null { template <typename Strategy> static inline typename area_result<Geometry, Strategy>::type apply(Geometry const& geometry, Strategy const& strategy) { return calculate_null::apply < typename area_result<Geometry, Strategy>::type >(geometry, strategy); } }; template <typename Geometry> struct area<Geometry, box_tag> : detail::area::box_area {}; template <typename Ring> struct area<Ring, ring_tag> : detail::area::ring_area < order_as_direction<geometry::point_order<Ring>::value>::value, geometry::closure<Ring>::value > {}; template <typename Polygon> struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum { template <typename Strategy> static inline typename area_result<Polygon, Strategy>::type apply(Polygon const& polygon, Strategy const& strategy) { return calculate_polygon_sum::apply< typename area_result<Polygon, Strategy>::type, detail::area::ring_area < order_as_direction<geometry::point_order<Polygon>::value>::value, geometry::closure<Polygon>::value > >(polygon, strategy); } }; template <typename MultiGeometry> struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum { template <typename Strategy> static inline typename area_result<MultiGeometry, Strategy>::type apply(MultiGeometry const& multi, Strategy const& strategy) { return multi_sum::apply < typename area_result<MultiGeometry, Strategy>::type, area<typename boost::range_value<MultiGeometry>::type> >(multi, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { template < typename Strategy, bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value > struct area { template <typename Geometry> static inline typename area_result<Geometry, Strategy>::type apply(Geometry const& geometry, Strategy const& strategy) { return dispatch::area<Geometry>::apply(geometry, strategy); } }; template <typename Strategy> struct area<Strategy, false> { template <typename Geometry> static auto apply(Geometry const& geometry, Strategy const& strategy) { using strategies::area::services::strategy_converter; return dispatch::area < Geometry >::apply(geometry, strategy_converter<Strategy>::get(strategy)); } }; template <> struct area<default_strategy, false> { template <typename Geometry> static inline typename area_result<Geometry>::type apply(Geometry const& geometry, default_strategy) { typedef typename strategies::area::services::default_strategy < Geometry >::type strategy_type; return dispatch::area<Geometry>::apply(geometry, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct area { template <typename Strategy> static inline typename area_result<Geometry, Strategy>::type apply(Geometry const& geometry, Strategy const& strategy) { return resolve_strategy::area<Strategy>::apply(geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type; template <typename Strategy> struct visitor : boost::static_visitor<typename area_result<variant_type, Strategy>::type> { Strategy const& m_strategy; visitor(Strategy const& strategy): m_strategy(strategy) {} template <typename Geometry> typename area_result<variant_type, Strategy>::type operator()(Geometry const& geometry) const { return area<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline typename area_result<variant_type, Strategy>::type apply(variant_type const& geometry, Strategy const& strategy) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{area} \ingroup area \details \details_calc{area}. \details_default_strategy The area algorithm calculates the surface area of all geometries having a surface, namely box, polygon, ring, multipolygon. The units are the square of the units used for the points defining the surface. If subject geometry is defined in meters, then area is calculated in square meters. The area calculation can be done in all three common coordinate systems, Cartesian, Spherical and Geographic as well. \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{area} \qbk{[include reference/algorithms/area.qbk]} \qbk{[heading Examples]} \qbk{[area] [area_output]} */ template <typename Geometry> inline typename area_result<Geometry>::type area(Geometry const& geometry) { concepts::check<Geometry const>(); // detail::throw_on_empty_input(geometry); return resolve_variant::area<Geometry>::apply(geometry, default_strategy()); } /*! \brief \brief_calc{area} \brief_strategy \ingroup area \details \details_calc{area} \brief_strategy. \details_strategy_reasons \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{Area} \param geometry \param_geometry \param strategy \param_strategy{area} \return \return_calc{area} \qbk{distinguish,with strategy} \qbk{ [include reference/algorithms/area.qbk] [heading Available Strategies] \* [link geometry.reference.strategies.strategy_area_cartesian Cartesian] \* [link geometry.reference.strategies.strategy_area_spherical Spherical] \* [link geometry.reference.strategies.strategy_area_geographic Geographic] [heading Example] [area_with_strategy] [area_with_strategy_output] } */ template <typename Geometry, typename Strategy> inline typename area_result<Geometry, Strategy>::type area(Geometry const& geometry, Strategy const& strategy) { concepts::check<Geometry const>(); // detail::throw_on_empty_input(geometry); return resolve_variant::area<Geometry>::apply(geometry, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP touches.hpp 0000644 00000002147 15125631657 0006746 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013, 2014, 2015, 2017. // Modifications copyright (c) 2013-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP #define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP #include <boost/geometry/algorithms/detail/touches/interface.hpp> #include <boost/geometry/algorithms/detail/touches/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP centroid.hpp 0000644 00000046346 15125631657 0007114 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP #define BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP #include <cstddef> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/throw_exception.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/exception.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/point_on_border.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/strategies/centroid.hpp> #include <boost/geometry/strategies/concepts/centroid_concept.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/util/for_each_coordinate.hpp> #include <boost/geometry/util/select_coordinate_type.hpp> #include <boost/geometry/algorithms/is_empty.hpp> #include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp> namespace boost { namespace geometry { #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) /*! \brief Centroid Exception \ingroup centroid \details The centroid_exception is thrown if the free centroid function is called with geometries for which the centroid cannot be calculated. For example: a linestring without points, a polygon without points, an empty multi-geometry. \qbk{ [heading See also] \* [link geometry.reference.algorithms.centroid the centroid function] } */ class centroid_exception : public geometry::exception { public: /*! \brief The default constructor */ inline centroid_exception() {} /*! \brief Returns the explanatory string. \return Pointer to a null-terminated string with explanatory information. */ virtual char const* what() const throw() { return "Boost.Geometry Centroid calculation exception"; } }; #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace centroid { struct centroid_point { template<typename Point, typename PointCentroid, typename Strategy> static inline void apply(Point const& point, PointCentroid& centroid, Strategy const&) { geometry::convert(point, centroid); } }; template < typename Indexed, typename Point, std::size_t Dimension = 0, std::size_t DimensionCount = dimension<Indexed>::type::value > struct centroid_indexed_calculator { typedef typename select_coordinate_type < Indexed, Point >::type coordinate_type; static inline void apply(Indexed const& indexed, Point& centroid) { coordinate_type const c1 = get<min_corner, Dimension>(indexed); coordinate_type const c2 = get<max_corner, Dimension>(indexed); coordinate_type m = c1 + c2; coordinate_type const two = 2; m /= two; set<Dimension>(centroid, m); centroid_indexed_calculator < Indexed, Point, Dimension + 1 >::apply(indexed, centroid); } }; template<typename Indexed, typename Point, std::size_t DimensionCount> struct centroid_indexed_calculator<Indexed, Point, DimensionCount, DimensionCount> { static inline void apply(Indexed const& , Point& ) { } }; struct centroid_indexed { template<typename Indexed, typename Point, typename Strategy> static inline void apply(Indexed const& indexed, Point& centroid, Strategy const&) { centroid_indexed_calculator < Indexed, Point >::apply(indexed, centroid); } }; // There is one thing where centroid is different from e.g. within. // If the ring has only one point, it might make sense that // that point is the centroid. template<typename Point, typename Range> inline bool range_ok(Range const& range, Point& centroid) { std::size_t const n = boost::size(range); if (n > 1) { return true; } else if (n <= 0) { #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) BOOST_THROW_EXCEPTION(centroid_exception()); #else return false; #endif } else // if (n == 1) { // Take over the first point in a "coordinate neutral way" geometry::convert(*boost::begin(range), centroid); return false; } //return true; // unreachable } /*! \brief Calculate the centroid of a Ring or a Linestring. */ template <closure_selector Closure> struct centroid_range_state { template<typename Ring, typename PointTransformer, typename Strategy> static inline void apply(Ring const& ring, PointTransformer const& transformer, Strategy const& strategy, typename Strategy::state_type& state) { boost::ignore_unused(strategy); typedef typename geometry::point_type<Ring const>::type point_type; typedef typename closeable_view<Ring const, Closure>::type view_type; typedef typename boost::range_iterator<view_type const>::type iterator_type; view_type view(ring); iterator_type it = boost::begin(view); iterator_type end = boost::end(view); if (it != end) { typename PointTransformer::result_type previous_pt = transformer.apply(*it); for ( ++it ; it != end ; ++it) { typename PointTransformer::result_type pt = transformer.apply(*it); strategy.apply(static_cast<point_type const&>(previous_pt), static_cast<point_type const&>(pt), state); previous_pt = pt; } } } }; template <closure_selector Closure> struct centroid_range { template<typename Range, typename Point, typename Strategy> static inline bool apply(Range const& range, Point& centroid, Strategy const& strategy) { if (range_ok(range, centroid)) { // prepare translation transformer translating_transformer<Range> transformer(*boost::begin(range)); typename Strategy::state_type state; centroid_range_state<Closure>::apply(range, transformer, strategy, state); if ( strategy.result(state, centroid) ) { // translate the result back transformer.apply_reverse(centroid); return true; } } return false; } }; /*! \brief Centroid of a polygon. \note Because outer ring is clockwise, inners are counter clockwise, triangle approach is OK and works for polygons with rings. */ struct centroid_polygon_state { template<typename Polygon, typename PointTransformer, typename Strategy> static inline void apply(Polygon const& poly, PointTransformer const& transformer, Strategy const& strategy, typename Strategy::state_type& state) { typedef typename ring_type<Polygon>::type ring_type; typedef centroid_range_state<geometry::closure<ring_type>::value> per_ring; per_ring::apply(exterior_ring(poly), transformer, strategy, state); typename interior_return_type<Polygon const>::type rings = interior_rings(poly); for (typename detail::interior_iterator<Polygon const>::type it = boost::begin(rings); it != boost::end(rings); ++it) { per_ring::apply(*it, transformer, strategy, state); } } }; struct centroid_polygon { template<typename Polygon, typename Point, typename Strategy> static inline bool apply(Polygon const& poly, Point& centroid, Strategy const& strategy) { if (range_ok(exterior_ring(poly), centroid)) { // prepare translation transformer translating_transformer<Polygon> transformer(*boost::begin(exterior_ring(poly))); typename Strategy::state_type state; centroid_polygon_state::apply(poly, transformer, strategy, state); if ( strategy.result(state, centroid) ) { // translate the result back transformer.apply_reverse(centroid); return true; } } return false; } }; /*! \brief Building block of a multi-point, to be used as Policy in the more generec centroid_multi */ struct centroid_multi_point_state { template <typename Point, typename PointTransformer, typename Strategy> static inline void apply(Point const& point, PointTransformer const& transformer, Strategy const& strategy, typename Strategy::state_type& state) { boost::ignore_unused(strategy); strategy.apply(static_cast<Point const&>(transformer.apply(point)), state); } }; /*! \brief Generic implementation which calls a policy to calculate the centroid of the total of its single-geometries \details The Policy is, in general, the single-version, with state. So detail::centroid::centroid_polygon_state is used as a policy for this detail::centroid::centroid_multi */ template <typename Policy> struct centroid_multi { template <typename Multi, typename Point, typename Strategy> static inline bool apply(Multi const& multi, Point& centroid, Strategy const& strategy) { #if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW) // If there is nothing in any of the ranges, it is not possible // to calculate the centroid if (geometry::is_empty(multi)) { BOOST_THROW_EXCEPTION(centroid_exception()); } #endif // prepare translation transformer translating_transformer<Multi> transformer(multi); typename Strategy::state_type state; for (typename boost::range_iterator<Multi const>::type it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, transformer, strategy, state); } if ( strategy.result(state, centroid) ) { // translate the result back transformer.apply_reverse(centroid); return true; } return false; } }; template <typename Algorithm> struct centroid_linear_areal { template <typename Geometry, typename Point, typename Strategy> static inline void apply(Geometry const& geom, Point& centroid, Strategy const& strategy) { if ( ! Algorithm::apply(geom, centroid, strategy) ) { geometry::point_on_border(centroid, geom); } } }; }} // namespace detail::centroid #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct centroid: not_implemented<Tag> {}; template <typename Geometry> struct centroid<Geometry, point_tag> : detail::centroid::centroid_point {}; template <typename Box> struct centroid<Box, box_tag> : detail::centroid::centroid_indexed {}; template <typename Segment> struct centroid<Segment, segment_tag> : detail::centroid::centroid_indexed {}; template <typename Ring> struct centroid<Ring, ring_tag> : detail::centroid::centroid_linear_areal < detail::centroid::centroid_range<geometry::closure<Ring>::value> > {}; template <typename Linestring> struct centroid<Linestring, linestring_tag> : detail::centroid::centroid_linear_areal < detail::centroid::centroid_range<closed> > {}; template <typename Polygon> struct centroid<Polygon, polygon_tag> : detail::centroid::centroid_linear_areal < detail::centroid::centroid_polygon > {}; template <typename MultiLinestring> struct centroid<MultiLinestring, multi_linestring_tag> : detail::centroid::centroid_linear_areal < detail::centroid::centroid_multi < detail::centroid::centroid_range_state<closed> > > {}; template <typename MultiPolygon> struct centroid<MultiPolygon, multi_polygon_tag> : detail::centroid::centroid_linear_areal < detail::centroid::centroid_multi < detail::centroid::centroid_polygon_state > > {}; template <typename MultiPoint> struct centroid<MultiPoint, multi_point_tag> : detail::centroid::centroid_multi < detail::centroid::centroid_multi_point_state > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { template <typename Geometry> struct centroid { template <typename Point, typename Strategy> static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy) { dispatch::centroid<Geometry>::apply(geometry, out, strategy); } template <typename Point> static inline void apply(Geometry const& geometry, Point& out, default_strategy) { typedef typename strategy::centroid::services::default_strategy < typename cs_tag<Geometry>::type, typename tag_cast < typename tag<Geometry>::type, pointlike_tag, linear_tag, areal_tag >::type, dimension<Geometry>::type::value, Point, Geometry >::type strategy_type; dispatch::centroid<Geometry>::apply(geometry, out, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct centroid { template <typename Point, typename Strategy> static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy) { concepts::check_concepts_and_equal_dimensions<Point, Geometry const>(); resolve_strategy::centroid<Geometry>::apply(geometry, out, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Point, typename Strategy> struct visitor: boost::static_visitor<void> { Point& m_out; Strategy const& m_strategy; visitor(Point& out, Strategy const& strategy) : m_out(out), m_strategy(strategy) {} template <typename Geometry> void operator()(Geometry const& geometry) const { centroid<Geometry>::apply(geometry, m_out, m_strategy); } }; template <typename Point, typename Strategy> static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Point& out, Strategy const& strategy) { boost::apply_visitor(visitor<Point, Strategy>(out, strategy), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{centroid} \brief_strategy \ingroup centroid \details \details_calc{centroid,geometric center (or: center of mass)}. \details_strategy_reasons \tparam Geometry \tparam_geometry \tparam Point \tparam_point \tparam Strategy \tparam_strategy{Centroid} \param geometry \param_geometry \param c \param_point \param_set{centroid} \param strategy \param_strategy{centroid} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/centroid.qbk]} \qbk{[include reference/algorithms/centroid_strategies.qbk]} } */ template<typename Geometry, typename Point, typename Strategy> inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy) { resolve_variant::centroid<Geometry>::apply(geometry, c, strategy); } /*! \brief \brief_calc{centroid} \ingroup centroid \details \details_calc{centroid,geometric center (or: center of mass)}. \details_default_strategy \tparam Geometry \tparam_geometry \tparam Point \tparam_point \param geometry \param_geometry \param c The calculated centroid will be assigned to this point reference \qbk{[include reference/algorithms/centroid.qbk]} \qbk{ [heading Example] [centroid] [centroid_output] } */ template<typename Geometry, typename Point> inline void centroid(Geometry const& geometry, Point& c) { geometry::centroid(geometry, c, default_strategy()); } /*! \brief \brief_calc{centroid} \ingroup centroid \details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}. \tparam Point \tparam_point \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{centroid} \qbk{[include reference/algorithms/centroid.qbk]} */ template<typename Point, typename Geometry> inline Point return_centroid(Geometry const& geometry) { Point c; geometry::centroid(geometry, c); return c; } /*! \brief \brief_calc{centroid} \brief_strategy \ingroup centroid \details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}. \details_strategy_reasons \tparam Point \tparam_point \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{centroid} \param geometry \param_geometry \param strategy \param_strategy{centroid} \return \return_calc{centroid} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/centroid.qbk]} \qbk{[include reference/algorithms/centroid_strategies.qbk]} */ template<typename Point, typename Geometry, typename Strategy> inline Point return_centroid(Geometry const& geometry, Strategy const& strategy) { Point c; geometry::centroid(geometry, c, strategy); return c; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP is_empty.hpp 0000644 00000011607 15125631657 0007126 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // 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_IS_EMPTY_HPP #define BOOST_GEOMETRY_ALGORITHMS_IS_EMPTY_HPP #include <boost/range/begin.hpp> #include <boost/range/empty.hpp> #include <boost/range/end.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/check_iterator_range.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace is_empty { struct always_not_empty { template <typename Geometry> static inline bool apply(Geometry const&) { return false; } }; struct range_is_empty { template <typename Range> static inline bool apply(Range const& range) { return boost::empty(range); } }; class polygon_is_empty { template <typename InteriorRings> static inline bool check_interior_rings(InteriorRings const& interior_rings) { return check_iterator_range < range_is_empty, true // allow empty range >::apply(boost::begin(interior_rings), boost::end(interior_rings)); } public: template <typename Polygon> static inline bool apply(Polygon const& polygon) { return boost::empty(exterior_ring(polygon)) && check_interior_rings(interior_rings(polygon)); } }; template <typename Policy = range_is_empty> struct multi_is_empty { template <typename MultiGeometry> static inline bool apply(MultiGeometry const& multigeometry) { return check_iterator_range < Policy, true // allow empty range >::apply(boost::begin(multigeometry), boost::end(multigeometry)); } }; }} // namespace detail::is_empty #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct is_empty : not_implemented<Tag> {}; template <typename Geometry> struct is_empty<Geometry, point_tag> : detail::is_empty::always_not_empty {}; template <typename Geometry> struct is_empty<Geometry, box_tag> : detail::is_empty::always_not_empty {}; template <typename Geometry> struct is_empty<Geometry, segment_tag> : detail::is_empty::always_not_empty {}; template <typename Geometry> struct is_empty<Geometry, linestring_tag> : detail::is_empty::range_is_empty {}; template <typename Geometry> struct is_empty<Geometry, ring_tag> : detail::is_empty::range_is_empty {}; template <typename Geometry> struct is_empty<Geometry, polygon_tag> : detail::is_empty::polygon_is_empty {}; template <typename Geometry> struct is_empty<Geometry, multi_point_tag> : detail::is_empty::range_is_empty {}; template <typename Geometry> struct is_empty<Geometry, multi_linestring_tag> : detail::is_empty::multi_is_empty<> {}; template <typename Geometry> struct is_empty<Geometry, multi_polygon_tag> : detail::is_empty::multi_is_empty<detail::is_empty::polygon_is_empty> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct is_empty { static inline bool apply(Geometry const& geometry) { concepts::check<Geometry const>(); return dispatch::is_empty<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct is_empty<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor : boost::static_visitor<bool> { template <typename Geometry> inline bool operator()(Geometry const& geometry) const { return is_empty<Geometry>::apply(geometry); } }; static bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) { return boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief \brief_check{is the empty set} \ingroup is_empty \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_check{is the empty set} \qbk{[include reference/algorithms/is_empty.qbk]} */ template <typename Geometry> inline bool is_empty(Geometry const& geometry) { return resolve_variant::is_empty<Geometry>::apply(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_IS_EMPTY_HPP correct_closure.hpp 0000644 00000014010 15125631657 0010461 0 ustar 00 // Boost.Geometry // Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP #define BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP #include <cstddef> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/disjoint.hpp> #include <boost/geometry/algorithms/detail/multi_modify.hpp> namespace boost { namespace geometry { // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable : 4127) #endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace correct_closure { template <typename Geometry> struct nop { static inline void apply(Geometry& ) {} }; // Close a ring, if not closed, or open it template <typename Ring> struct close_or_open_ring { static inline void apply(Ring& r) { if (boost::size(r) <= 2) { return; } bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1)); closure_selector const s = geometry::closure<Ring>::value; if (disjoint && s == closed) { // Close it by adding first point geometry::append(r, *boost::begin(r)); } else if (! disjoint && s != closed) { // Open it by removing last point geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1); } } }; // Close/open exterior ring and all its interior rings template <typename Polygon> struct close_or_open_polygon { typedef typename ring_type<Polygon>::type ring_type; static inline void apply(Polygon& poly) { close_or_open_ring<ring_type>::apply(exterior_ring(poly)); typename interior_return_type<Polygon>::type rings = interior_rings(poly); for (typename detail::interior_iterator<Polygon>::type it = boost::begin(rings); it != boost::end(rings); ++it) { close_or_open_ring<ring_type>::apply(*it); } } }; }} // namespace detail::correct_closure #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct correct_closure: not_implemented<Tag> {}; template <typename Point> struct correct_closure<Point, point_tag> : detail::correct_closure::nop<Point> {}; template <typename LineString> struct correct_closure<LineString, linestring_tag> : detail::correct_closure::nop<LineString> {}; template <typename Segment> struct correct_closure<Segment, segment_tag> : detail::correct_closure::nop<Segment> {}; template <typename Box> struct correct_closure<Box, box_tag> : detail::correct_closure::nop<Box> {}; template <typename Ring> struct correct_closure<Ring, ring_tag> : detail::correct_closure::close_or_open_ring<Ring> {}; template <typename Polygon> struct correct_closure<Polygon, polygon_tag> : detail::correct_closure::close_or_open_polygon<Polygon> {}; template <typename MultiPoint> struct correct_closure<MultiPoint, multi_point_tag> : detail::correct_closure::nop<MultiPoint> {}; template <typename MultiLineString> struct correct_closure<MultiLineString, multi_linestring_tag> : detail::correct_closure::nop<MultiLineString> {}; template <typename Geometry> struct correct_closure<Geometry, multi_polygon_tag> : detail::multi_modify < Geometry, detail::correct_closure::close_or_open_polygon < typename boost::range_value<Geometry>::type > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct correct_closure { static inline void apply(Geometry& geometry) { concepts::check<Geometry const>(); dispatch::correct_closure<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct correct_closure<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<void> { template <typename Geometry> void operator()(Geometry& geometry) const { correct_closure<Geometry>::apply(geometry); } }; static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) { visitor vis; boost::apply_visitor(vis, geometry); } }; } // namespace resolve_variant /*! \brief Closes or opens a geometry, according to its type \details Corrects a geometry w.r.t. closure points to all rings which do not have a closing point and are typed as they should have one, the first point is appended. \ingroup correct_closure \tparam Geometry \tparam_geometry \param geometry \param_geometry which will be corrected if necessary */ template <typename Geometry> inline void correct_closure(Geometry& geometry) { resolve_variant::correct_closure<Geometry>::apply(geometry); } #if defined(_MSC_VER) #pragma warning(pop) #endif }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP not_implemented.hpp 0000644 00000003262 15125631657 0010456 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015-2020. // Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_NOT_IMPLEMENTED_HPP #define BOOST_GEOMETRY_ALGORITHMS_NOT_IMPLEMENTED_HPP #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> namespace boost { namespace geometry { namespace nyi { struct not_implemented_tag {}; template <typename ...Terms> struct not_implemented_error { #ifndef BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD # define BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD false #endif BOOST_GEOMETRY_STATIC_ASSERT( BOOST_GEOMETRY_IMPLEMENTATION_STATUS_BUILD, "This operation is not or not yet implemented.", Terms...); }; } template <typename ...Terms> struct not_implemented : nyi::not_implemented_tag, nyi::not_implemented_error<Terms...> {}; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_NOT_IMPLEMENTED_HPP dispatch/is_valid.hpp 0000644 00000001743 15125631657 0010666 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP #include <boost/geometry/core/tag.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type, // for multi-geometries: determines if empty multi-geometries are allowed bool AllowEmptyMultiGeometries = true > struct is_valid : not_implemented<Geometry> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP dispatch/distance.hpp 0000644 00000004620 15125631657 0010663 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014, 2018. // Modifications copyright (c) 2014-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/algorithms/detail/distance/default_strategies.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/strategies/distance.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Strategy = typename detail::distance::default_strategy < Geometry1, Geometry2 >::type, typename Tag1 = typename tag_cast < typename tag<Geometry1>::type, segment_tag, box_tag, linear_tag, areal_tag >::type, typename Tag2 = typename tag_cast < typename tag<Geometry2>::type, segment_tag, box_tag, linear_tag, areal_tag >::type, typename StrategyTag = typename strategy::distance::services::tag < Strategy >::type, bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value > struct distance: not_implemented<Tag1, Tag2> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISTANCE_HPP dispatch/expand.hpp 0000644 00000003214 15125631657 0010346 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2015, 2017, 2018. // Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_EXPAND_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_EXPAND_HPP #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/strategies/compare.hpp> #include <boost/geometry/policies/compare.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename GeometryOut, typename Geometry, typename TagOut = typename tag<GeometryOut>::type, typename Tag = typename tag<Geometry>::type > struct expand : not_implemented<TagOut, Tag> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_EXPAND_HPP dispatch/is_simple.hpp 0000644 00000001544 15125631657 0011057 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP #include <boost/geometry/core/tag.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct is_simple : not_implemented<Geometry> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP dispatch/disjoint.hpp 0000644 00000005234 15125631657 0010716 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2013-2018. // Modifications copyright (c) 2013-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP #include <cstddef> #include <boost/geometry/core/coordinate_dimension.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, std::size_t DimensionCount = dimension<Geometry1>::type::value, typename Tag1 = typename tag_cast < typename tag<Geometry1>::type, segment_tag, box_tag, linear_tag, areal_tag >::type, typename Tag2 = typename tag_cast < typename tag<Geometry2>::type, segment_tag, box_tag, linear_tag, areal_tag >::type, bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value > struct disjoint : not_implemented<Geometry1, Geometry2> {}; // If reversal is needed, perform it template < typename Geometry1, typename Geometry2, std::size_t DimensionCount, typename Tag1, typename Tag2 > struct disjoint<Geometry1, Geometry2, DimensionCount, Tag1, Tag2, true> { template <typename Strategy> static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) { return disjoint < Geometry2, Geometry1, DimensionCount, Tag2, Tag1 >::apply(g2, g1, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_DISJOINT_HPP dispatch/envelope.hpp 0000644 00000002631 15125631657 0010706 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2015 Bruno Lalande, Paris, France. // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2015, 2018. // Modifications copyright (c) 2015-2018, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_ENVELOPE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_ENVELOPE_HPP #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct envelope : not_implemented<Tag> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_ENVELOPE_HPP for_each.hpp 0000644 00000036111 15125631657 0007040 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_FOR_EACH_HPP #define BOOST_GEOMETRY_ALGORITHMS_FOR_EACH_HPP #include <algorithm> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/reference.hpp> #include <boost/range/value_type.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/segment.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/util/type_traits.hpp> #include <boost/geometry/views/detail/indexed_point_view.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace for_each { struct fe_point_point { template <typename Point, typename Functor> static inline bool apply(Point& point, Functor&& f) { return f(point); } }; struct fe_segment_point { template <typename Point, typename Functor> static inline bool apply(Point& , Functor&& ) { // TODO: if non-const, we should extract the points from the segment // and call the functor on those two points //model::referring_segment<Point> s(point, point); //return f(s); return true; } }; struct fe_point_segment { template <typename Segment, typename Functor> static inline bool apply(Segment& s, Functor&& f) { // Or should we guarantee that the type of points is // point_type<Segment>::type ? geometry::detail::indexed_point_view<Segment, 0> p0(s); geometry::detail::indexed_point_view<Segment, 1> p1(s); return f(p0) && f(p1); } }; struct fe_segment_segment { template <typename Segment, typename Functor> static inline bool apply(Segment& s, Functor&& f) { // Or should we guarantee that the type of segment is // referring_segment<...> ? return f(s); } }; template <typename Range> struct fe_range_value { typedef util::transcribe_const_t < Range, typename boost::range_value<Range>::type > type; }; template <typename Range> struct fe_point_type { typedef util::transcribe_const_t < Range, typename point_type<Range>::type > type; }; template <typename Range> struct fe_point_type_is_referencable { static const bool value = std::is_const<Range>::value || std::is_same < typename boost::range_reference<Range>::type, typename fe_point_type<Range>::type& >::value; }; template < typename Range, bool UseReferences = fe_point_type_is_referencable<Range>::value > struct fe_point_call_f { template <typename Iterator, typename Functor> static inline bool apply(Iterator it, Functor&& f) { // Implementation for real references (both const and mutable) // and const proxy references. typedef typename fe_point_type<Range>::type point_type; point_type& p = *it; return f(p); } }; template <typename Range> struct fe_point_call_f<Range, false> { template <typename Iterator, typename Functor> static inline bool apply(Iterator it, Functor&& f) { // Implementation for proxy mutable references. // Temporary point has to be created and assigned afterwards. typedef typename fe_point_type<Range>::type point_type; point_type p = *it; bool result = f(p); *it = p; return result; } }; struct fe_point_range { template <typename Range, typename Functor> static inline bool apply(Range& range, Functor&& f) { auto const end = boost::end(range); for (auto it = boost::begin(range); it != end; ++it) { if (! fe_point_call_f<Range>::apply(it, f)) { return false; } } return true; } }; template < typename Range, bool UseReferences = fe_point_type_is_referencable<Range>::value > struct fe_segment_call_f { template <typename Iterator, typename Functor> static inline bool apply(Iterator it0, Iterator it1, Functor&& f) { // Implementation for real references (both const and mutable) // and const proxy references. // If const proxy references are returned by iterators // then const real references here prevents temporary // objects from being destroyed. typedef typename fe_point_type<Range>::type point_type; point_type& p0 = *it0; point_type& p1 = *it1; model::referring_segment<point_type> s(p0, p1); return f(s); } }; template <typename Range> struct fe_segment_call_f<Range, false> { template <typename Iterator, typename Functor> static inline bool apply(Iterator it0, Iterator it1, Functor&& f) { // Mutable proxy references returned by iterators. // Temporary points have to be created and assigned afterwards. typedef typename fe_point_type<Range>::type point_type; point_type p0 = *it0; point_type p1 = *it1; model::referring_segment<point_type> s(p0, p1); bool result = f(s); *it0 = p0; *it1 = p1; return result; } }; template <closure_selector Closure> struct fe_segment_range_with_closure { template <typename Range, typename Functor> static inline bool apply(Range& range, Functor&& f) { auto it = boost::begin(range); auto const end = boost::end(range); if (it == end) { return true; } auto previous = it++; if (it == end) { return fe_segment_call_f<Range>::apply(previous, previous, f); } while (it != end) { if (! fe_segment_call_f<Range>::apply(previous, it, f)) { return false; } previous = it++; } return true; } }; template <> struct fe_segment_range_with_closure<open> { template <typename Range, typename Functor> static inline bool apply(Range& range, Functor&& f) { fe_segment_range_with_closure<closed>::apply(range, f); auto const begin = boost::begin(range); auto end = boost::end(range); if (begin == end) { return true; } --end; if (begin == end) { // single point ranges already handled in closed case above return true; } return fe_segment_call_f<Range>::apply(end, begin, f); } }; struct fe_segment_range { template <typename Range, typename Functor> static inline bool apply(Range& range, Functor&& f) { return fe_segment_range_with_closure < closure<Range>::value >::apply(range, f); } }; template <typename RangePolicy> struct for_each_polygon { template <typename Polygon, typename Functor> static inline bool apply(Polygon& poly, Functor&& f) { if (! RangePolicy::apply(exterior_ring(poly), f)) { return false; } typename interior_return_type<Polygon>::type rings = interior_rings(poly); auto const end = boost::end(rings); for (auto it = boost::begin(rings); it != end; ++it) { // NOTE: Currently lvalue iterator required if (! RangePolicy::apply(*it, f)) { return false; } } return true; } }; // Implementation of multi, for both point and segment, // just calling the single version. template <typename SinglePolicy> struct for_each_multi { template <typename MultiGeometry, typename Functor> static inline bool apply(MultiGeometry& multi, Functor&& f) { auto const end = boost::end(multi); for (auto it = boost::begin(multi); it != end; ++it) { // NOTE: Currently lvalue iterator required if (! SinglePolicy::apply(*it, f)) { return false; } } return true; } }; }} // namespace detail::for_each #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type > struct for_each_point: not_implemented<Tag> {}; template <typename Point> struct for_each_point<Point, point_tag> : detail::for_each::fe_point_point {}; template <typename Segment> struct for_each_point<Segment, segment_tag> : detail::for_each::fe_point_segment {}; template <typename Linestring> struct for_each_point<Linestring, linestring_tag> : detail::for_each::fe_point_range {}; template <typename Ring> struct for_each_point<Ring, ring_tag> : detail::for_each::fe_point_range {}; template <typename Polygon> struct for_each_point<Polygon, polygon_tag> : detail::for_each::for_each_polygon < detail::for_each::fe_point_range > {}; template <typename MultiGeometry> struct for_each_point<MultiGeometry, multi_tag> : detail::for_each::for_each_multi < // Specify the dispatch of the single-version as policy for_each_point < typename detail::for_each::fe_range_value < MultiGeometry >::type > > {}; template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct for_each_segment: not_implemented<Tag> {}; template <typename Point> struct for_each_segment<Point, point_tag> : detail::for_each::fe_segment_point // empty {}; template <typename Segment> struct for_each_segment<Segment, segment_tag> : detail::for_each::fe_segment_segment {}; template <typename Linestring> struct for_each_segment<Linestring, linestring_tag> : detail::for_each::fe_segment_range {}; template <typename Ring> struct for_each_segment<Ring, ring_tag> : detail::for_each::fe_segment_range {}; template <typename Polygon> struct for_each_segment<Polygon, polygon_tag> : detail::for_each::for_each_polygon < detail::for_each::fe_segment_range > {}; template <typename MultiPoint> struct for_each_segment<MultiPoint, multi_point_tag> : detail::for_each::fe_segment_point // empty {}; template <typename MultiLinestring> struct for_each_segment<MultiLinestring, multi_linestring_tag> : detail::for_each::for_each_multi < detail::for_each::fe_segment_range > {}; template <typename MultiPolygon> struct for_each_segment<MultiPolygon, multi_polygon_tag> : detail::for_each::for_each_multi < detail::for_each::for_each_polygon < detail::for_each::fe_segment_range > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH template<typename Geometry, typename UnaryPredicate> inline bool all_points_of(Geometry& geometry, UnaryPredicate p) { concepts::check<Geometry>(); return dispatch::for_each_point<Geometry>::apply(geometry, p); } template<typename Geometry, typename UnaryPredicate> inline bool all_segments_of(Geometry const& geometry, UnaryPredicate p) { concepts::check<Geometry const>(); return dispatch::for_each_segment<Geometry const>::apply(geometry, p); } template<typename Geometry, typename UnaryPredicate> inline bool any_point_of(Geometry& geometry, UnaryPredicate p) { concepts::check<Geometry>(); return ! dispatch::for_each_point<Geometry>::apply(geometry, [&](auto&& pt) { return ! p(pt); }); } template<typename Geometry, typename UnaryPredicate> inline bool any_segment_of(Geometry const& geometry, UnaryPredicate p) { concepts::check<Geometry const>(); return ! dispatch::for_each_segment<Geometry const>::apply(geometry, [&](auto&& s) { return ! p(s); }); } template<typename Geometry, typename UnaryPredicate> inline bool none_point_of(Geometry& geometry, UnaryPredicate p) { concepts::check<Geometry>(); return dispatch::for_each_point<Geometry>::apply(geometry, [&](auto&& pt) { return ! p(pt); }); } template<typename Geometry, typename UnaryPredicate> inline bool none_segment_of(Geometry const& geometry, UnaryPredicate p) { concepts::check<Geometry const>(); return dispatch::for_each_segment<Geometry const>::apply(geometry, [&](auto&& s) { return ! p(s); }); } /*! \brief \brf_for_each{point} \details \det_for_each{point} \ingroup for_each \param geometry \param_geometry \param f \par_for_each_f{point} \tparam Geometry \tparam_geometry \tparam Functor \tparam_functor \qbk{[include reference/algorithms/for_each_point.qbk]} \qbk{[heading Example]} \qbk{[for_each_point] [for_each_point_output]} \qbk{[for_each_point_const] [for_each_point_const_output]} */ template<typename Geometry, typename Functor> inline Functor for_each_point(Geometry& geometry, Functor f) { concepts::check<Geometry>(); dispatch::for_each_point<Geometry>::apply(geometry, [&](auto&& pt) { f(pt); // TODO: Implement separate function? return true; }); return f; } /*! \brief \brf_for_each{segment} \details \det_for_each{segment} \ingroup for_each \param geometry \param_geometry \param f \par_for_each_f{segment} \tparam Geometry \tparam_geometry \tparam Functor \tparam_functor \qbk{[include reference/algorithms/for_each_segment.qbk]} \qbk{[heading Example]} \qbk{[for_each_segment_const] [for_each_segment_const_output]} */ template<typename Geometry, typename Functor> inline Functor for_each_segment(Geometry& geometry, Functor f) { concepts::check<Geometry>(); dispatch::for_each_segment<Geometry>::apply(geometry, [&](auto&& s) { f(s); // TODO: Implement separate function? return true; }); return f; } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_FOR_EACH_HPP length.hpp 0000644 00000021606 15125631657 0006556 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP #define BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP #include <iterator> #include <boost/concept_check.hpp> #include <boost/core/ignore_unused.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/iterator.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/cs.hpp> #include <boost/geometry/core/closure.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/detail/calculate_null.hpp> #include <boost/geometry/algorithms/detail/multi_sum.hpp> // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/views/closeable_view.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/default_length_result.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace length { template<typename Segment> struct segment_length { template <typename Strategy> static inline typename default_length_result<Segment>::type apply( Segment const& segment, Strategy const& strategy) { boost::ignore_unused(strategy); typedef typename point_type<Segment>::type point_type; point_type p1, p2; geometry::detail::assign_point_from_index<0>(segment, p1); geometry::detail::assign_point_from_index<1>(segment, p2); return strategy.apply(p1, p2); } }; /*! \brief Internal, calculates length of a linestring using iterator pairs and specified strategy \note for_each could be used here, now that point_type is changed by boost range iterator */ template<typename Range, closure_selector Closure> struct range_length { typedef typename default_length_result<Range>::type return_type; template <typename Strategy> static inline return_type apply( Range const& range, Strategy const& strategy) { boost::ignore_unused(strategy); typedef typename closeable_view<Range const, Closure>::type view_type; typedef typename boost::range_iterator < view_type const >::type iterator_type; return_type sum = return_type(); view_type view(range); iterator_type it = boost::begin(view), end = boost::end(view); if(it != end) { for(iterator_type previous = it++; it != end; ++previous, ++it) { // Add point-point distance using the return type belonging // to strategy sum += strategy.apply(*previous, *it); } } return sum; } }; }} // namespace detail::length #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct length : detail::calculate_null { typedef typename default_length_result<Geometry>::type return_type; template <typename Strategy> static inline return_type apply(Geometry const& geometry, Strategy const& strategy) { return calculate_null::apply<return_type>(geometry, strategy); } }; template <typename Geometry> struct length<Geometry, linestring_tag> : detail::length::range_length<Geometry, closed> {}; // RING: length is currently 0; it might be argued that it is the "perimeter" template <typename Geometry> struct length<Geometry, segment_tag> : detail::length::segment_length<Geometry> {}; template <typename MultiLinestring> struct length<MultiLinestring, multi_linestring_tag> : detail::multi_sum { template <typename Strategy> static inline typename default_length_result<MultiLinestring>::type apply(MultiLinestring const& multi, Strategy const& strategy) { return multi_sum::apply < typename default_length_result<MultiLinestring>::type, detail::length::range_length < typename boost::range_value<MultiLinestring>::type, closed // no need to close it explicitly > >(multi, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct length { template <typename Geometry, typename Strategy> static inline typename default_length_result<Geometry>::type apply(Geometry const& geometry, Strategy const& strategy) { return dispatch::length<Geometry>::apply(geometry, strategy); } template <typename Geometry> static inline typename default_length_result<Geometry>::type apply(Geometry const& geometry, default_strategy) { typedef typename strategy::distance::services::default_strategy < point_tag, point_tag, typename point_type<Geometry>::type >::type strategy_type; return dispatch::length<Geometry>::apply(geometry, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template <typename Geometry> struct length { template <typename Strategy> static inline typename default_length_result<Geometry>::type apply(Geometry const& geometry, Strategy const& strategy) { return resolve_strategy::length::apply(geometry, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct length<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { typedef typename default_length_result < boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >::type result_type; template <typename Strategy> struct visitor : static_visitor<result_type> { Strategy const& m_strategy; visitor(Strategy const& strategy) : m_strategy(strategy) {} template <typename Geometry> inline typename default_length_result<Geometry>::type operator()(Geometry const& geometry) const { return length<Geometry>::apply(geometry, m_strategy); } }; template <typename Strategy> static inline result_type apply( variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, Strategy const& strategy ) { return boost::apply_visitor(visitor<Strategy>(strategy), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{length} \ingroup length \details \details_calc{length, length (the sum of distances between consecutive points)}. \details_default_strategy \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{length} \qbk{[include reference/algorithms/length.qbk]} \qbk{[length] [length_output]} */ template<typename Geometry> inline typename default_length_result<Geometry>::type length(Geometry const& geometry) { concepts::check<Geometry const>(); // detail::throw_on_empty_input(geometry); return resolve_variant::length<Geometry>::apply(geometry, default_strategy()); } /*! \brief \brief_calc{length} \brief_strategy \ingroup length \details \details_calc{length, length (the sum of distances between consecutive points)} \brief_strategy. \details_strategy_reasons \tparam Geometry \tparam_geometry \tparam Strategy \tparam_strategy{distance} \param geometry \param_geometry \param strategy \param_strategy{distance} \return \return_calc{length} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/length.qbk]} \qbk{[length_with_strategy] [length_with_strategy_output]} */ template<typename Geometry, typename Strategy> inline typename default_length_result<Geometry>::type length(Geometry const& geometry, Strategy const& strategy) { concepts::check<Geometry const>(); // detail::throw_on_empty_input(geometry); return resolve_variant::length<Geometry>::apply(geometry, strategy); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP relate.hpp 0000644 00000001202 15125631657 0006537 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_RELATE_HPP #define BOOST_GEOMETRY_ALGORITHMS_RELATE_HPP #include <boost/geometry/algorithms/detail/relate/interface.hpp> #include <boost/geometry/algorithms/detail/relate/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_RELATE_HPP unique.hpp 0000644 00000011364 15125631657 0006603 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_UNIQUE_HPP #define BOOST_GEOMETRY_ALGORITHMS_UNIQUE_HPP #include <algorithm> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/policies/compare.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace unique { struct range_unique { template <typename Range, typename ComparePolicy> static inline void apply(Range& range, ComparePolicy const& policy) { typename boost::range_iterator<Range>::type it = std::unique ( boost::begin(range), boost::end(range), policy ); traits::resize<Range>::apply(range, it - boost::begin(range)); } }; struct polygon_unique { template <typename Polygon, typename ComparePolicy> static inline void apply(Polygon& polygon, ComparePolicy const& policy) { range_unique::apply(exterior_ring(polygon), policy); typename interior_return_type<Polygon>::type rings = interior_rings(polygon); for (typename detail::interior_iterator<Polygon>::type it = boost::begin(rings); it != boost::end(rings); ++it) { range_unique::apply(*it, policy); } } }; template <typename Policy> struct multi_unique { template <typename MultiGeometry, typename ComparePolicy> static inline void apply(MultiGeometry& multi, ComparePolicy const& compare) { for (typename boost::range_iterator<MultiGeometry>::type it = boost::begin(multi); it != boost::end(multi); ++it) { Policy::apply(*it, compare); } } }; }} // namespace detail::unique #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag<Geometry>::type > struct unique { template <typename ComparePolicy> static inline void apply(Geometry&, ComparePolicy const& ) {} }; template <typename Ring> struct unique<Ring, ring_tag> : detail::unique::range_unique {}; template <typename LineString> struct unique<LineString, linestring_tag> : detail::unique::range_unique {}; template <typename Polygon> struct unique<Polygon, polygon_tag> : detail::unique::polygon_unique {}; // For points, unique is not applicable and does nothing // (Note that it is not "spatially unique" but that it removes duplicate coordinates, // like std::unique does). Spatially unique is "dissolve" which can (or will be) // possible for multi-points as well, removing points at the same location. template <typename MultiLineString> struct unique<MultiLineString, multi_linestring_tag> : detail::unique::multi_unique<detail::unique::range_unique> {}; template <typename MultiPolygon> struct unique<MultiPolygon, multi_polygon_tag> : detail::unique::multi_unique<detail::unique::polygon_unique> {}; } // namespace dispatch #endif /*! \brief \brief_calc{minimal set} \ingroup unique \details \details_calc{unique,minimal set (where duplicate consecutive points are removed)}. \tparam Geometry \tparam_geometry \param geometry \param_geometry which will be made unique \qbk{[include reference/algorithms/unique.qbk]} */ template <typename Geometry> inline void unique(Geometry& geometry) { concepts::check<Geometry>(); // Default strategy is the default point-comparison policy typedef geometry::equal_to < typename geometry::point_type<Geometry>::type > policy; dispatch::unique<Geometry>::apply(geometry, policy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_UNIQUE_HPP discrete_frechet_distance.hpp 0000644 00000017244 15125631657 0012454 0 ustar 00 // Boost.Geometry // Copyright (c) 2018 Yaghyavardhan Singh Khangarot, Hyderabad, India. // Contributed and/or modified by Yaghyavardhan Singh Khangarot, // as part of Google Summer of Code 2018 program. // This file was modified by Oracle on 2018. // Modifications copyright (c) 2018 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISCRETE_FRECHET_DISTANCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISCRETE_FRECHET_DISTANCE_HPP #include <algorithm> #ifdef BOOST_GEOMETRY_DEBUG_FRECHET_DISTANCE #include <iostream> #endif #include <iterator> #include <utility> #include <vector> #include <limits> #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/assert.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/distance_result.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace discrete_frechet_distance { template <typename size_type1 , typename size_type2,typename result_type> class coup_mat { public: coup_mat(size_type1 w, size_type2 h) : m_data(w * h,-1), m_width(w), m_height(h) {} result_type & operator()(size_type1 i, size_type2 j) { BOOST_GEOMETRY_ASSERT(i < m_width && j < m_height); return m_data[j * m_width + i]; } private: std::vector<result_type> m_data; size_type1 m_width; size_type2 m_height; }; struct linestring_linestring { template <typename Linestring1, typename Linestring2, typename Strategy> static inline typename distance_result < typename point_type<Linestring1>::type, typename point_type<Linestring2>::type, Strategy >::type apply(Linestring1 const& ls1, Linestring2 const& ls2, Strategy const& strategy) { typedef typename distance_result < typename point_type<Linestring1>::type, typename point_type<Linestring2>::type, Strategy >::type result_type; typedef typename boost::range_size<Linestring1>::type size_type1; typedef typename boost::range_size<Linestring2>::type size_type2; boost::geometry::detail::throw_on_empty_input(ls1); boost::geometry::detail::throw_on_empty_input(ls2); size_type1 const a = boost::size(ls1); size_type2 const b = boost::size(ls2); //Coupling Matrix CoupMat(a,b,-1); coup_mat<size_type1,size_type2,result_type> coup_matrix(a,b); result_type const not_feasible = -100; //findin the Coupling Measure for (size_type1 i = 0 ; i < a ; i++ ) { for(size_type2 j=0;j<b;j++) { result_type dis = strategy.apply(range::at(ls1,i), range::at(ls2,j)); if(i==0 && j==0) coup_matrix(i,j) = dis; else if(i==0 && j>0) coup_matrix(i,j) = (std::max)(coup_matrix(i,j-1), dis); else if(i>0 && j==0) coup_matrix(i,j) = (std::max)(coup_matrix(i-1,j), dis); else if(i>0 && j>0) coup_matrix(i,j) = (std::max)((std::min)(coup_matrix(i,j-1), (std::min)(coup_matrix(i-1,j), coup_matrix(i-1,j-1))), dis); else coup_matrix(i,j) = not_feasible; } } #ifdef BOOST_GEOMETRY_DEBUG_FRECHET_DISTANCE //Print CoupLing Matrix for(size_type i = 0; i <a; i++) { for(size_type j = 0; j <b; j++) std::cout << coup_matrix(i,j) << " "; std::cout << std::endl; } #endif return coup_matrix(a-1,b-1); } }; }} // namespace detail::frechet_distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > struct discrete_frechet_distance : not_implemented<Tag1, Tag2> {}; template <typename Linestring1, typename Linestring2> struct discrete_frechet_distance < Linestring1, Linestring2, linestring_tag, linestring_tag > : detail::discrete_frechet_distance::linestring_linestring {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH /*! \brief Calculate discrete Frechet distance between two geometries (currently works for LineString-LineString) using specified strategy. \ingroup discrete_frechet_distance \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy A type fulfilling a DistanceStrategy concept \param geometry1 Input geometry \param geometry2 Input geometry \param strategy Distance strategy to be used to calculate Pt-Pt distance \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/discrete_frechet_distance.qbk]} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)] \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)] [/ \* more (currently extensions): Vincenty\, Andoyer (geographic) ] [heading Example] [discrete_frechet_distance_strategy] [discrete_frechet_distance_strategy_output] } */ template <typename Geometry1, typename Geometry2, typename Strategy> inline typename distance_result < typename point_type<Geometry1>::type, typename point_type<Geometry2>::type, Strategy >::type discrete_frechet_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return dispatch::discrete_frechet_distance < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } // Algorithm overload using default Pt-Pt distance strategy /*! \brief Calculate discrete Frechet distance between two geometries (currently work for LineString-LineString). \ingroup discrete_frechet_distance \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 Input geometry \param geometry2 Input geometry \qbk{[include reference/algorithms/discrete_frechet_distance.qbk]} \qbk{ [heading Example] [discrete_frechet_distance] [discrete_frechet_distance_output] } */ template <typename Geometry1, typename Geometry2> inline typename distance_result < typename point_type<Geometry1>::type, typename point_type<Geometry2>::type >::type discrete_frechet_distance(Geometry1 const& geometry1, Geometry2 const& geometry2) { typedef typename strategy::distance::services::default_strategy < point_tag, point_tag, typename point_type<Geometry1>::type, typename point_type<Geometry2>::type >::type strategy_type; return discrete_frechet_distance(geometry1, geometry2, strategy_type()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISCRETE_FRECHET_DISTANCE_HPP discrete_hausdorff_distance.hpp 0000644 00000026021 15125631657 0013006 0 ustar 00 // Boost.Geometry // Copyright (c) 2018 Yaghyavardhan Singh Khangarot, Hyderabad, India. // Contributed and/or modified by Yaghyavardhan Singh Khangarot, // as part of Google Summer of Code 2018 program. // This file was modified by Oracle on 2018. // Modifications copyright (c) 2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP #include <algorithm> #ifdef BOOST_GEOMETRY_DEBUG_HAUSDORFF_DISTANCE #include <iostream> #endif #include <iterator> #include <utility> #include <vector> #include <limits> #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/strategies/distance.hpp> #include <boost/geometry/strategies/distance_result.hpp> #include <boost/geometry/util/range.hpp> #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE #include <boost/geometry/index/rtree.hpp> #endif // BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace discrete_hausdorff_distance { struct point_range { template <typename Point, typename Range, typename Strategy> static inline typename distance_result < typename point_type<Point>::type, typename point_type<Range>::type, Strategy >::type apply(Point const& pnt, Range const& rng, Strategy const& strategy) { typedef typename distance_result < typename point_type<Point>::type, typename point_type<Range>::type, Strategy >::type result_type; typedef typename boost::range_size<Range>::type size_type; size_type const n = boost::size(rng); result_type dis_min = 0; bool is_dis_min_set = false; for (size_type i = 0 ; i < n ; i++) { result_type dis_temp = strategy.apply(pnt, range::at(rng, i)); if (! is_dis_min_set || dis_temp < dis_min) { dis_min = dis_temp; is_dis_min_set = true; } } return dis_min; } }; struct range_range { template <typename Range1, typename Range2, typename Strategy> static inline typename distance_result < typename point_type<Range1>::type, typename point_type<Range2>::type, Strategy >::type apply(Range1 const& r1, Range2 const& r2, Strategy const& strategy) { typedef typename distance_result < typename point_type<Range1>::type, typename point_type<Range2>::type, Strategy >::type result_type; typedef typename boost::range_size<Range1>::type size_type; boost::geometry::detail::throw_on_empty_input(r1); boost::geometry::detail::throw_on_empty_input(r2); size_type const n = boost::size(r1); result_type dis_max = 0; #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE namespace bgi = boost::geometry::index; typedef typename point_type<Range1>::type point_t; typedef bgi::rtree<point_t, bgi::linear<4> > rtree_type; rtree_type rtree(boost::begin(r2), boost::end(r2)); point_t res; #endif for (size_type i = 0 ; i < n ; i++) { #ifdef BOOST_GEOMETRY_ENABLE_SIMILARITY_RTREE size_type found = rtree.query(bgi::nearest(range::at(r1, i), 1), &res); result_type dis_min = strategy.apply(range::at(r1,i), res); #else result_type dis_min = point_range::apply(range::at(r1, i), r2, strategy); #endif if (dis_min > dis_max ) { dis_max = dis_min; } } return dis_max; } }; struct range_multi_range { template <typename Range, typename Multi_range, typename Strategy> static inline typename distance_result < typename point_type<Range>::type, typename point_type<Multi_range>::type, Strategy >::type apply(Range const& rng, Multi_range const& mrng, Strategy const& strategy) { typedef typename distance_result < typename point_type<Range>::type, typename point_type<Multi_range>::type, Strategy >::type result_type; typedef typename boost::range_size<Multi_range>::type size_type; boost::geometry::detail::throw_on_empty_input(rng); boost::geometry::detail::throw_on_empty_input(mrng); size_type b = boost::size(mrng); result_type haus_dis = 0; for (size_type j = 0 ; j < b ; j++) { result_type dis_max = range_range::apply(rng, range::at(mrng, j), strategy); if (dis_max > haus_dis) { haus_dis = dis_max; } } return haus_dis; } }; struct multi_range_multi_range { template <typename Multi_Range1, typename Multi_range2, typename Strategy> static inline typename distance_result < typename point_type<Multi_Range1>::type, typename point_type<Multi_range2>::type, Strategy >::type apply(Multi_Range1 const& mrng1, Multi_range2 const& mrng2, Strategy const& strategy) { typedef typename distance_result < typename point_type<Multi_Range1>::type, typename point_type<Multi_range2>::type, Strategy >::type result_type; typedef typename boost::range_size<Multi_Range1>::type size_type; boost::geometry::detail::throw_on_empty_input(mrng1); boost::geometry::detail::throw_on_empty_input(mrng2); size_type n = boost::size(mrng1); result_type haus_dis = 0; for (size_type i = 0 ; i < n ; i++) { result_type dis_max = range_multi_range::apply(range::at(mrng1, i), mrng2, strategy); if (dis_max > haus_dis) { haus_dis = dis_max; } } return haus_dis; } }; }} // namespace detail::hausdorff_distance #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type > struct discrete_hausdorff_distance : not_implemented<Tag1, Tag2> {}; // Specialization for point and multi_point template <typename Point, typename MultiPoint> struct discrete_hausdorff_distance<Point, MultiPoint, point_tag, multi_point_tag> : detail::discrete_hausdorff_distance::point_range {}; // Specialization for linestrings template <typename Linestring1, typename Linestring2> struct discrete_hausdorff_distance<Linestring1, Linestring2, linestring_tag, linestring_tag> : detail::discrete_hausdorff_distance::range_range {}; // Specialization for multi_point-multi_point template <typename MultiPoint1, typename MultiPoint2> struct discrete_hausdorff_distance<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag> : detail::discrete_hausdorff_distance::range_range {}; // Specialization for Linestring and MultiLinestring template <typename Linestring, typename MultiLinestring> struct discrete_hausdorff_distance<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag> : detail::discrete_hausdorff_distance::range_multi_range {}; // Specialization for MultiLinestring and MultiLinestring template <typename MultiLinestring1, typename MultiLinestring2> struct discrete_hausdorff_distance<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag> : detail::discrete_hausdorff_distance::multi_range_multi_range {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH // Algorithm overload using explicitly passed Pt-Pt distance strategy /*! \brief Calculate discrete Hausdorff distance between two geometries (currently works for LineString-LineString, MultiPoint-MultiPoint, Point-MultiPoint, MultiLineString-MultiLineString) using specified strategy. \ingroup discrete_hausdorff_distance \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Strategy A type fulfilling a DistanceStrategy concept \param geometry1 Input geometry \param geometry2 Input geometry \param strategy Distance strategy to be used to calculate Pt-Pt distance \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/discrete_hausdorff_distance.qbk]} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)] \* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)] [/ \* more (currently extensions): Vincenty\, Andoyer (geographic) ] [heading Example] [discrete_hausdorff_distance_strategy] [discrete_hausdorff_distance_strategy_output] } */ template <typename Geometry1, typename Geometry2, typename Strategy> inline typename distance_result < typename point_type<Geometry1>::type, typename point_type<Geometry2>::type, Strategy >::type discrete_hausdorff_distance(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { return dispatch::discrete_hausdorff_distance < Geometry1, Geometry2 >::apply(geometry1, geometry2, strategy); } /*! \brief Calculate discrete Hausdorff distance between two geometries (currently works for LineString-LineString, MultiPoint-MultiPoint, Point-MultiPoint, MultiLineString-MultiLineString). \ingroup discrete_hausdorff_distance \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 Input geometry \param geometry2 Input geometry \qbk{[include reference/algorithms/discrete_hausdorff_distance.qbk]} \qbk{ [heading Example] [discrete_hausdorff_distance] [discrete_hausdorff_distance_output] } */ template <typename Geometry1, typename Geometry2> inline typename distance_result < typename point_type<Geometry1>::type, typename point_type<Geometry2>::type >::type discrete_hausdorff_distance(Geometry1 const& geometry1, Geometry2 const& geometry2) { typedef typename strategy::distance::services::default_strategy < point_tag, point_tag, typename point_type<Geometry1>::type, typename point_type<Geometry2>::type >::type strategy_type; return discrete_hausdorff_distance(geometry1, geometry2, strategy_type()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DISCRETE_HAUSDORFF_DISTANCE_HPP validity_failure_type.hpp 0000644 00000007144 15125631657 0011673 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2015, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_VALIDITY_FAILURE_TYPE_HPP #define BOOST_GEOMETRY_ALGORITHMS_VALIDITY_FAILURE_TYPE_HPP namespace boost { namespace geometry { /*! \brief Enumerates the possible validity failure types for a geometry \ingroup enum \details The enumeration validity_failure_type enumerates the possible reasons for which a geometry may be found as invalid by the is_valid algorithm. Besides the values that indicate invalidity, there is an additional value (no_failure) that indicates validity. \qbk{ [heading See also] [link geometry.reference.algorithms.is_valid The is_valid algorithm taking a reference to validity_failure_type as second argument] } */ enum validity_failure_type { /// The geometry is valid /// no_failure = 0, /// The geometry has a very small number of points, e.g., less /// than 2 for linestrings, less than 3 for open rings, a closed /// multi-polygon that contains a polygon with less than 4 points, etc. /// (applies to linestrings, rings, polygons, multi-linestrings /// and multi-polygons) failure_few_points = 10, /// The topological dimension of the geometry is smaller than its /// dimension, e.g., a linestring with 3 identical points, an open /// polygon with an interior ring consisting of 3 collinear points, etc. /// (applies to linear and areal geometries, including segments /// and boxes) failure_wrong_topological_dimension = 11, /// The geometry contains spikes /// (applies to linear and areal geometries) failure_spikes = 12, /// The geometry has (consecutive) duplicate points /// (applies to areal geometries only) failure_duplicate_points = 13, /// The geometry is defined as closed, the starting/ending points /// are not equal /// (applies to areal geometries only) failure_not_closed = 20, // for areal geometries /// The geometry has invalid self-intersections. /// (applies to areal geometries only) failure_self_intersections = 21, // for areal geometries /// The actual orientation of the geometry is different from the one defined /// (applies to areal geometries only) failure_wrong_orientation = 22, // for areal geometries /// The geometry contains interior rings that lie outside the exterior ring /// (applies to polygons and multi-polygons only) failure_interior_rings_outside = 30, // for (multi-)polygons /// The geometry has nested interior rings /// (applies to polygons and multi-polygons only) failure_nested_interior_rings = 31, // for (multi-)polygons /// The interior of the geometry is disconnected /// (applies to polygons and multi-polygons only) failure_disconnected_interior = 32, // for (multi-)polygons /// The multi-polygon contains polygons whose interiors are not disjoint /// (applies to multi-polygons only) failure_intersecting_interiors = 40, // for multi-polygons /// The top-right corner of the box is lexicographically smaller /// than its bottom-left corner /// (applies to boxes only) failure_wrong_corner_order = 50, // for boxes /// The geometry has at least one point with an invalid coordinate /// (for example, the coordinate is a NaN) failure_invalid_coordinate = 60 }; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_VALIDITY_FAILURE_TYPE_HPP union.hpp 0000644 00000051561 15125631657 0006430 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_UNION_HPP #define BOOST_GEOMETRY_ALGORITHMS_UNION_HPP #include <boost/range/value_type.hpp> #include <boost/geometry/core/point_order.hpp> #include <boost/geometry/core/reverse_dispatch.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/algorithms/detail/overlay/overlay.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/util/range.hpp> #include <boost/geometry/algorithms/detail/intersection/multi.hpp> #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> #include <boost/geometry/algorithms/detail/overlay/linear_linear.hpp> #include <boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry1, typename Geometry2, typename GeometryOut, typename TagIn1 = typename tag<Geometry1>::type, typename TagIn2 = typename tag<Geometry2>::type, typename TagOut = typename detail::setop_insert_output_tag<GeometryOut>::type, typename CastedTagIn1 = typename geometry::tag_cast<TagIn1, areal_tag, linear_tag, pointlike_tag>::type, typename CastedTagIn2 = typename geometry::tag_cast<TagIn2, areal_tag, linear_tag, pointlike_tag>::type, typename CastedTagOut = typename geometry::tag_cast<TagOut, areal_tag, linear_tag, pointlike_tag>::type, bool Reverse = geometry::reverse_dispatch<Geometry1, Geometry2>::type::value > struct union_insert: not_implemented<TagIn1, TagIn2, TagOut> {}; // If reversal is needed, perform it first template < typename Geometry1, typename Geometry2, typename GeometryOut, typename TagIn1, typename TagIn2, typename TagOut, typename CastedTagIn1, typename CastedTagIn2, typename CastedTagOut > struct union_insert < Geometry1, Geometry2, GeometryOut, TagIn1, TagIn2, TagOut, CastedTagIn1, CastedTagIn2, CastedTagOut, true > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return union_insert < Geometry2, Geometry1, GeometryOut >::apply(g2, g1, robust_policy, out, strategy); } }; template < typename Geometry1, typename Geometry2, typename GeometryOut, typename TagIn1, typename TagIn2, typename TagOut > struct union_insert < Geometry1, Geometry2, GeometryOut, TagIn1, TagIn2, TagOut, areal_tag, areal_tag, areal_tag, false > : detail::overlay::overlay < Geometry1, Geometry2, detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value, GeometryOut, overlay_union > {}; // dispatch for union of linear geometries template < typename Linear1, typename Linear2, typename LineStringOut, typename TagIn1, typename TagIn2 > struct union_insert < Linear1, Linear2, LineStringOut, TagIn1, TagIn2, linestring_tag, linear_tag, linear_tag, linear_tag, false > : detail::overlay::linear_linear_linestring < Linear1, Linear2, LineStringOut, overlay_union > {}; // dispatch for point-like geometries template < typename PointLike1, typename PointLike2, typename PointOut, typename TagIn1, typename TagIn2 > struct union_insert < PointLike1, PointLike2, PointOut, TagIn1, TagIn2, point_tag, pointlike_tag, pointlike_tag, pointlike_tag, false > : detail::overlay::union_pointlike_pointlike_point < PointLike1, PointLike2, PointOut > {}; template < typename Geometry1, typename Geometry2, typename SingleTupledOut, typename TagIn1, typename TagIn2, typename CastedTagIn > struct union_insert < Geometry1, Geometry2, SingleTupledOut, TagIn1, TagIn2, detail::tupled_output_tag, CastedTagIn, CastedTagIn, detail::tupled_output_tag, false > { typedef typename geometry::detail::single_tag_from_base_tag < CastedTagIn >::type single_tag; typedef detail::expect_output < Geometry1, Geometry2, SingleTupledOut, single_tag > expect_check; typedef typename geometry::detail::output_geometry_access < SingleTupledOut, single_tag, single_tag > access; template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { access::get(out) = union_insert < Geometry2, Geometry1, typename access::type >::apply(g2, g1, robust_policy, access::get(out), strategy); return out; } }; template < typename Geometry1, typename Geometry2, typename SingleTupledOut, typename SingleTag1, typename SingleTag2, bool Geometry1LesserTopoDim = (topological_dimension<Geometry1>::value < topological_dimension<Geometry2>::value) > struct union_insert_tupled_different { typedef typename geometry::detail::output_geometry_access < SingleTupledOut, SingleTag1, SingleTag1 > access1; typedef typename geometry::detail::output_geometry_access < SingleTupledOut, SingleTag2, SingleTag2 > access2; template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { access1::get(out) = geometry::dispatch::intersection_insert < Geometry1, Geometry2, typename access1::type, overlay_difference, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value >::apply(g1, g2, robust_policy, access1::get(out), strategy); access2::get(out) = geometry::detail::convert_to_output < Geometry2, typename access2::type >::apply(g2, access2::get(out)); return out; } }; template < typename Geometry1, typename Geometry2, typename SingleTupledOut, typename SingleTag1, typename SingleTag2 > struct union_insert_tupled_different < Geometry1, Geometry2, SingleTupledOut, SingleTag1, SingleTag2, false > { template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return union_insert_tupled_different < Geometry2, Geometry1, SingleTupledOut, SingleTag2, SingleTag1, true >::apply(g2, g1, robust_policy, out, strategy); } }; template < typename Geometry1, typename Geometry2, typename SingleTupledOut, typename TagIn1, typename TagIn2, typename CastedTagIn1, typename CastedTagIn2 > struct union_insert < Geometry1, Geometry2, SingleTupledOut, TagIn1, TagIn2, detail::tupled_output_tag, CastedTagIn1, CastedTagIn2, detail::tupled_output_tag, false > { typedef typename geometry::detail::single_tag_from_base_tag < CastedTagIn1 >::type single_tag1; typedef detail::expect_output < Geometry1, Geometry2, SingleTupledOut, single_tag1 > expect_check1; typedef typename geometry::detail::single_tag_from_base_tag < CastedTagIn2 >::type single_tag2; typedef detail::expect_output < Geometry1, Geometry2, SingleTupledOut, single_tag2 > expect_check2; template <typename RobustPolicy, typename OutputIterator, typename Strategy> static inline OutputIterator apply(Geometry1 const& g1, Geometry2 const& g2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return union_insert_tupled_different < Geometry1, Geometry2, SingleTupledOut, single_tag1, single_tag2 >::apply(g1, g2, robust_policy, out, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace union_ { /*! \brief_calc2{union} \ingroup union \details \details_calc2{union_insert, spatial set theoretic union}. \details_insert{union} \tparam GeometryOut output geometry type, must be specified \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator output iterator \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{union} \return \return_out */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator > inline OutputIterator union_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); geometry::detail::output_geometry_concept_check<GeometryOut>::apply(); typename strategy::intersection::services::default_strategy < typename cs_tag<GeometryOut>::type >::type strategy; typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2 >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return dispatch::union_insert < Geometry1, Geometry2, GeometryOut >::apply(geometry1, geometry2, robust_policy, out, strategy); } }} // namespace detail::union_ #endif // DOXYGEN_NO_DETAIL namespace resolve_strategy { struct union_ { template < typename Geometry1, typename Geometry2, typename Collection, typename Strategy > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection & output_collection, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_value < Collection >::type single_out; typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); dispatch::union_insert < Geometry1, Geometry2, single_out >::apply(geometry1, geometry2, robust_policy, geometry::detail::output_geometry_back_inserter(output_collection), strategy); } template < typename Geometry1, typename Geometry2, typename Collection > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection & output_collection, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; apply(geometry1, geometry2, output_collection, strategy_type()); } }; } // resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct union_ { template <typename Collection, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); //concepts::check<typename boost::range_value<Collection>::type>(); geometry::detail::output_geometry_concept_check < typename geometry::detail::output_geometry_value < Collection >::type >::apply(); resolve_strategy::union_::apply(geometry1, geometry2, output_collection, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct union_<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Geometry2 const& m_geometry2; Collection& m_output_collection; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) : m_geometry2(geometry2) , m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry1> void operator()(Geometry1 const& geometry1) const { union_ < Geometry1, Geometry2 >::apply(geometry1, m_geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(geometry2, output_collection, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct union_<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Geometry1 const& m_geometry1; Collection& m_output_collection; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Collection& output_collection, Strategy const& strategy) : m_geometry1(geometry1) , m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry2> void operator()(Geometry2 const& geometry2) const { union_ < Geometry1, Geometry2 >::apply(m_geometry1, geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(Geometry1 const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(geometry1, output_collection, strategy), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct union_<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Collection& m_output_collection; Strategy const& m_strategy; visitor(Collection& output_collection, Strategy const& strategy) : m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> void operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { union_ < Geometry1, Geometry2 >::apply(geometry1, geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(output_collection, strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief Combines two geometries which each other \ingroup union \details \details_calc2{union, spatial set theoretic union}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection output collection, either a multi-geometry, or a std::vector<Geometry> / std::deque<Geometry> etc \tparam Strategy \tparam_strategy{Union_} \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection \param strategy \param_strategy{union_} \note Called union_ because union is a reserved word. \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/union.qbk]} */ template < typename Geometry1, typename Geometry2, typename Collection, typename Strategy > inline void union_(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { resolve_variant::union_ < Geometry1, Geometry2 >::apply(geometry1, geometry2, output_collection, strategy); } /*! \brief Combines two geometries which each other \ingroup union \details \details_calc2{union, spatial set theoretic union}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection output collection, either a multi-geometry, or a std::vector<Geometry> / std::deque<Geometry> etc \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection \note Called union_ because union is a reserved word. \qbk{[include reference/algorithms/union.qbk]} */ template < typename Geometry1, typename Geometry2, typename Collection > inline void union_(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection) { resolve_variant::union_ < Geometry1, Geometry2 >::apply(geometry1, geometry2, output_collection, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_UNION_HPP clear.hpp 0000644 00000012301 15125631657 0006353 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP #include <type_traits> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/not_implemented.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/tag_cast.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace clear { template <typename Geometry> struct collection_clear { static inline void apply(Geometry& geometry) { traits::clear<Geometry>::apply(geometry); } }; template <typename Polygon> struct polygon_clear { static inline void apply(Polygon& polygon) { traits::clear < typename std::remove_reference < typename traits::interior_mutable_type<Polygon>::type >::type >::apply(interior_rings(polygon)); traits::clear < typename std::remove_reference < typename traits::ring_mutable_type<Polygon>::type >::type >::apply(exterior_ring(polygon)); } }; template <typename Geometry> struct no_action { static inline void apply(Geometry& ) { } }; }} // namespace detail::clear #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type > struct clear: not_implemented<Tag> {}; // Point/box/segment do not have clear. So specialize to do nothing. template <typename Geometry> struct clear<Geometry, point_tag> : detail::clear::no_action<Geometry> {}; template <typename Geometry> struct clear<Geometry, box_tag> : detail::clear::no_action<Geometry> {}; template <typename Geometry> struct clear<Geometry, segment_tag> : detail::clear::no_action<Geometry> {}; template <typename Geometry> struct clear<Geometry, linestring_tag> : detail::clear::collection_clear<Geometry> {}; template <typename Geometry> struct clear<Geometry, ring_tag> : detail::clear::collection_clear<Geometry> {}; // Polygon can (indirectly) use std for clear template <typename Polygon> struct clear<Polygon, polygon_tag> : detail::clear::polygon_clear<Polygon> {}; template <typename Geometry> struct clear<Geometry, multi_tag> : detail::clear::collection_clear<Geometry> {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct clear { static inline void apply(Geometry& geometry) { dispatch::clear<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct clear<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: static_visitor<void> { template <typename Geometry> inline void operator()(Geometry& geometry) const { clear<Geometry>::apply(geometry); } }; static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry) { boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief Clears a linestring, ring or polygon (exterior+interiors) or multi* \details Generic function to clear a geometry. All points will be removed from the collection or collections making up the geometry. In most cases this is equivalent to the .clear() method of a std::vector<...>. In the case of a polygon, this clear functionality is automatically called for the exterior ring, and for the interior ring collection. In the case of a point, boxes and segments, nothing will happen. \ingroup clear \tparam Geometry \tparam_geometry \param geometry \param_geometry which will be cleared \note points and boxes cannot be cleared, instead they can be set to zero by "assign_zero" \qbk{[include reference/algorithms/clear.qbk]} */ template <typename Geometry> inline void clear(Geometry& geometry) { concepts::check<Geometry>(); resolve_variant::clear<Geometry>::apply(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP assign.hpp 0000644 00000025137 15125631657 0006564 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2014 Samuel Debionne, Grenoble, France. // This file was modified by Oracle on 2020. // Modifications copyright (c) 2020 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP #define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP #include <cstddef> #include <boost/concept/requires.hpp> #include <boost/concept_check.hpp> #include <boost/numeric/conversion/bounds.hpp> #include <boost/numeric/conversion/cast.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/assign_box_corners.hpp> #include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/algorithms/detail/assign_values.hpp> #include <boost/geometry/algorithms/convert.hpp> #include <boost/geometry/algorithms/append.hpp> #include <boost/geometry/algorithms/clear.hpp> #include <boost/geometry/arithmetic/arithmetic.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/static_assert.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/util/for_each_coordinate.hpp> namespace boost { namespace geometry { /*! \brief Assign a range of points to a linestring, ring or polygon \note The point-type of the range might be different from the point-type of the geometry \ingroup assign \tparam Geometry \tparam_geometry \tparam Range \tparam_range_point \param geometry \param_geometry \param range \param_range_point \qbk{ [heading Notes] [note Assign automatically clears the geometry before assigning (use append if you don't want that)] [heading Example] [assign_points] [assign_points_output] [heading See also] \* [link geometry.reference.algorithms.append append] } */ template <typename Geometry, typename Range> inline void assign_points(Geometry& geometry, Range const& range) { concepts::check<Geometry>(); clear(geometry); geometry::append(geometry, range, -1, 0); } /*! \brief assign to a box inverse infinite \details The assign_inverse function initialize a 2D or 3D box with large coordinates, the min corner is very large, the max corner is very small. This is a convenient starting point to collect the minimum bounding box of a geometry. \ingroup assign \tparam Geometry \tparam_geometry \param geometry \param_geometry \qbk{ [heading Example] [assign_inverse] [assign_inverse_output] [heading See also] \* [link geometry.reference.algorithms.make.make_inverse make_inverse] } */ template <typename Geometry> inline void assign_inverse(Geometry& geometry) { concepts::check<Geometry>(); dispatch::assign_inverse < typename tag<Geometry>::type, Geometry >::apply(geometry); } /*! \brief assign zero values to a box, point \ingroup assign \details The assign_zero function initializes a 2D or 3D point or box with coordinates of zero \tparam Geometry \tparam_geometry \param geometry \param_geometry */ template <typename Geometry> inline void assign_zero(Geometry& geometry) { concepts::check<Geometry>(); dispatch::assign_zero < typename tag<Geometry>::type, Geometry >::apply(geometry); } /*! \brief Assign two coordinates to a geometry (usually a 2D point) \ingroup assign \tparam Geometry \tparam_geometry \tparam Type \tparam_numeric to specify the coordinates \param geometry \param_geometry \param c1 \param_x \param c2 \param_y \qbk{distinguish, 2 coordinate values} \qbk{ [heading Example] [assign_2d_point] [assign_2d_point_output] [heading See also] \* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make] } */ template <typename Geometry, typename Type> inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2) { concepts::check<Geometry>(); dispatch::assign < typename tag<Geometry>::type, Geometry, geometry::dimension<Geometry>::type::value >::apply(geometry, c1, c2); } /*! \brief Assign three values to a geometry (usually a 3D point) \ingroup assign \tparam Geometry \tparam_geometry \tparam Type \tparam_numeric to specify the coordinates \param geometry \param_geometry \param c1 \param_x \param c2 \param_y \param c3 \param_z \qbk{distinguish, 3 coordinate values} \qbk{ [heading Example] [assign_3d_point] [assign_3d_point_output] [heading See also] \* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make] } */ template <typename Geometry, typename Type> inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2, Type const& c3) { concepts::check<Geometry>(); dispatch::assign < typename tag<Geometry>::type, Geometry, geometry::dimension<Geometry>::type::value >::apply(geometry, c1, c2, c3); } /*! \brief Assign four values to a geometry (usually a box or segment) \ingroup assign \tparam Geometry \tparam_geometry \tparam Type \tparam_numeric to specify the coordinates \param geometry \param_geometry \param c1 First coordinate (usually x1) \param c2 Second coordinate (usually y1) \param c3 Third coordinate (usually x2) \param c4 Fourth coordinate (usually y2) \qbk{distinguish, 4 coordinate values} */ template <typename Geometry, typename Type> inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2, Type const& c3, Type const& c4) { concepts::check<Geometry>(); dispatch::assign < typename tag<Geometry>::type, Geometry, geometry::dimension<Geometry>::type::value >::apply(geometry, c1, c2, c3, c4); } namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct assign { static inline void apply(Geometry1& geometry1, const Geometry2& geometry2) { concepts::check<Geometry1>(); concepts::check<Geometry2 const>(); concepts::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>(); static bool const same_point_order = point_order<Geometry1>::value == point_order<Geometry2>::value; BOOST_GEOMETRY_STATIC_ASSERT( same_point_order, "Assign is not supported for different point orders.", Geometry1, Geometry2); static bool const same_closure = closure<Geometry1>::value == closure<Geometry2>::value; BOOST_GEOMETRY_STATIC_ASSERT( same_closure, "Assign is not supported for different closures.", Geometry1, Geometry2); dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { struct visitor: static_visitor<void> { Geometry2 const& m_geometry2; visitor(Geometry2 const& geometry2) : m_geometry2(geometry2) {} template <typename Geometry1> result_type operator()(Geometry1& geometry1) const { return assign < Geometry1, Geometry2 >::apply (geometry1, m_geometry2); } }; static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1, Geometry2 const& geometry2) { return boost::apply_visitor(visitor(geometry2), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: static_visitor<void> { Geometry1& m_geometry1; visitor(Geometry1 const& geometry1) : m_geometry1(geometry1) {} template <typename Geometry2> result_type operator()(Geometry2 const& geometry2) const { return assign < Geometry1, Geometry2 >::apply (m_geometry1, geometry2); } }; static inline void apply(Geometry1& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2) { return boost::apply_visitor(visitor(geometry1), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { struct visitor: static_visitor<void> { template <typename Geometry1, typename Geometry2> result_type operator()( Geometry1& geometry1, Geometry2 const& geometry2) const { return assign < Geometry1, Geometry2 >::apply (geometry1, geometry2); } }; static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2) { return boost::apply_visitor(visitor(), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief Assigns one geometry to another geometry \details The assign algorithm assigns one geometry, e.g. a BOX, to another geometry, e.g. a RING. This only works if it is possible and applicable. \ingroup assign \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \param geometry1 \param_geometry (target) \param geometry2 \param_geometry (source) \qbk{ [heading Example] [assign] [assign_output] [heading See also] \* [link geometry.reference.algorithms.convert convert] } */ template <typename Geometry1, typename Geometry2> inline void assign(Geometry1& geometry1, Geometry2 const& geometry2) { resolve_variant::assign<Geometry1, Geometry2>::apply(geometry1, geometry2); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP difference.hpp 0000644 00000040317 15125631657 0007367 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017, 2019, 2020. // Modifications copyright (c) 2017-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/algorithms/detail/intersection/multi.hpp> #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp> #include <boost/geometry/policies/robustness/get_rescale_policy.hpp> #include <boost/geometry/strategies/default_strategy.hpp> #include <boost/geometry/util/range.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace difference { template < typename Geometry1, typename Geometry2, typename SingleOut, typename OutTag = typename detail::setop_insert_output_tag<SingleOut>::type, bool ReturnGeometry1 = (topological_dimension<Geometry1>::value > topological_dimension<Geometry2>::value) > struct call_intersection_insert { template < typename OutputIterator, typename RobustPolicy, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return geometry::dispatch::intersection_insert < Geometry1, Geometry2, SingleOut, overlay_difference, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value >::apply(geometry1, geometry2, robust_policy, out, strategy); } }; template < typename Geometry1, typename Geometry2, typename SingleOut > struct call_intersection_insert_tupled_base { typedef typename geometry::detail::single_tag_from_base_tag < typename geometry::tag_cast < typename geometry::tag<Geometry1>::type, pointlike_tag, linear_tag, areal_tag >::type >::type single_tag; typedef detail::expect_output < Geometry1, Geometry2, SingleOut, single_tag > expect_check; typedef typename geometry::detail::output_geometry_access < SingleOut, single_tag, single_tag > access; }; template < typename Geometry1, typename Geometry2, typename SingleOut > struct call_intersection_insert < Geometry1, Geometry2, SingleOut, detail::tupled_output_tag, false > : call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut> { typedef call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut> base_t; template < typename OutputIterator, typename RobustPolicy, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { base_t::access::get(out) = call_intersection_insert < Geometry1, Geometry2, typename base_t::access::type >::apply(geometry1, geometry2, robust_policy, base_t::access::get(out), strategy); return out; } }; template < typename Geometry1, typename Geometry2, typename SingleOut > struct call_intersection_insert < Geometry1, Geometry2, SingleOut, detail::tupled_output_tag, true > : call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut> { typedef call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut> base_t; template < typename OutputIterator, typename RobustPolicy, typename Strategy > static inline OutputIterator apply(Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { base_t::access::get(out) = geometry::detail::convert_to_output < Geometry1, typename base_t::access::type >::apply(geometry1, base_t::access::get(out)); return out; } }; /*! \brief_calc2{difference} \brief_strategy \ingroup difference \details \details_calc2{difference_insert, spatial set theoretic difference} \brief_strategy. \details_inserter{difference} \tparam GeometryOut output geometry type, must be specified \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator output iterator \tparam Strategy \tparam_strategy_overlay \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{difference} \param strategy \param_strategy{difference} \return \return_out \qbk{distinguish,with strategy} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator, typename Strategy > inline OutputIterator difference_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out, Strategy const& strategy) { concepts::check<Geometry1 const>(); concepts::check<Geometry2 const>(); //concepts::check<GeometryOut>(); geometry::detail::output_geometry_concept_check<GeometryOut>::apply(); typedef typename geometry::rescale_overlay_policy_type < Geometry1, Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; rescale_policy_type robust_policy = geometry::get_rescale_policy<rescale_policy_type>( geometry1, geometry2, strategy); return geometry::detail::difference::call_intersection_insert < Geometry1, Geometry2, GeometryOut >::apply(geometry1, geometry2, robust_policy, out, strategy); } /*! \brief_calc2{difference} \ingroup difference \details \details_calc2{difference_insert, spatial set theoretic difference}. \details_insert{difference} \tparam GeometryOut output geometry type, must be specified \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam OutputIterator output iterator \param geometry1 \param_geometry \param geometry2 \param_geometry \param out \param_out{difference} \return \return_out \qbk{[include reference/algorithms/difference_insert.qbk]} */ template < typename GeometryOut, typename Geometry1, typename Geometry2, typename OutputIterator > inline OutputIterator difference_insert(Geometry1 const& geometry1, Geometry2 const& geometry2, OutputIterator out) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; return difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type()); } }} // namespace detail::difference #endif // DOXYGEN_NO_DETAIL namespace resolve_strategy { struct difference { template < typename Geometry1, typename Geometry2, typename Collection, typename Strategy > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection & output_collection, Strategy const& strategy) { typedef typename geometry::detail::output_geometry_value < Collection >::type single_out; detail::difference::difference_insert<single_out>( geometry1, geometry2, geometry::detail::output_geometry_back_inserter(output_collection), strategy); } template < typename Geometry1, typename Geometry2, typename Collection > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection & output_collection, default_strategy) { typedef typename strategy::relate::services::default_strategy < Geometry1, Geometry2 >::type strategy_type; apply(geometry1, geometry2, output_collection, strategy_type()); } }; } // resolve_strategy namespace resolve_variant { template <typename Geometry1, typename Geometry2> struct difference { template <typename Collection, typename Strategy> static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { resolve_strategy::difference::apply(geometry1, geometry2, output_collection, strategy); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2> struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2> { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Geometry2 const& m_geometry2; Collection& m_output_collection; Strategy const& m_strategy; visitor(Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) : m_geometry2(geometry2) , m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry1> void operator()(Geometry1 const& geometry1) const { difference < Geometry1, Geometry2 >::apply(geometry1, m_geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(geometry2, output_collection, strategy), geometry1); } }; template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)> struct difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Geometry1 const& m_geometry1; Collection& m_output_collection; Strategy const& m_strategy; visitor(Geometry1 const& geometry1, Collection& output_collection, Strategy const& strategy) : m_geometry1(geometry1) , m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry2> void operator()(Geometry2 const& geometry2) const { difference < Geometry1, Geometry2 >::apply(m_geometry1, geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(Geometry1 const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(geometry1, output_collection, strategy), geometry2); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)> struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> > { template <typename Collection, typename Strategy> struct visitor: static_visitor<> { Collection& m_output_collection; Strategy const& m_strategy; visitor(Collection& output_collection, Strategy const& strategy) : m_output_collection(output_collection) , m_strategy(strategy) {} template <typename Geometry1, typename Geometry2> void operator()(Geometry1 const& geometry1, Geometry2 const& geometry2) const { difference < Geometry1, Geometry2 >::apply(geometry1, geometry2, m_output_collection, m_strategy); } }; template <typename Collection, typename Strategy> static inline void apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2, Collection& output_collection, Strategy const& strategy) { boost::apply_visitor(visitor<Collection, Strategy>(output_collection, strategy), geometry1, geometry2); } }; } // namespace resolve_variant /*! \brief_calc2{difference} \ingroup difference \details \details_calc2{difference, spatial set theoretic difference}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection \tparam_output_collection \tparam Strategy \tparam_strategy{Difference} \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection \param strategy \param_strategy{difference} \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/difference.qbk]} */ template < typename Geometry1, typename Geometry2, typename Collection, typename Strategy > inline void difference(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection, Strategy const& strategy) { resolve_variant::difference < Geometry1, Geometry2 >::apply(geometry1, geometry2, output_collection, strategy); } /*! \brief_calc2{difference} \ingroup difference \details \details_calc2{difference, spatial set theoretic difference}. \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry \tparam Collection \tparam_output_collection \param geometry1 \param_geometry \param geometry2 \param_geometry \param output_collection the output collection \qbk{[include reference/algorithms/difference.qbk]} */ template < typename Geometry1, typename Geometry2, typename Collection > inline void difference(Geometry1 const& geometry1, Geometry2 const& geometry2, Collection& output_collection) { resolve_variant::difference < Geometry1, Geometry2 >::apply(geometry1, geometry2, output_collection, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP num_interior_rings.hpp 0000644 00000007340 15125631657 0011210 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2014 Bruno Lalande, Paris, France. // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2014-2020. // Modifications copyright (c) 2014-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_NUM_INTERIOR_RINGS_HPP #define BOOST_GEOMETRY_ALGORITHMS_NUM_INTERIOR_RINGS_HPP #include <cstddef> #include <boost/range/size.hpp> #include <boost/range/value_type.hpp> #include <boost/variant/apply_visitor.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/variant/variant_fwd.hpp> #include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/algorithms/detail/counting.hpp> #include <boost/geometry/geometries/concepts/check.hpp> namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template <typename Geometry, typename Tag = typename tag<Geometry>::type> struct num_interior_rings : detail::counting::other_count<0> {}; template <typename Polygon> struct num_interior_rings<Polygon, polygon_tag> { static inline std::size_t apply(Polygon const& polygon) { return boost::size(geometry::interior_rings(polygon)); } }; template <typename MultiPolygon> struct num_interior_rings<MultiPolygon, multi_polygon_tag> : detail::counting::multi_count < num_interior_rings < typename boost::range_value<MultiPolygon const>::type > > {}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_variant { template <typename Geometry> struct num_interior_rings { static inline std::size_t apply(Geometry const& geometry) { concepts::check<Geometry const>(); return dispatch::num_interior_rings<Geometry>::apply(geometry); } }; template <BOOST_VARIANT_ENUM_PARAMS(typename T)> struct num_interior_rings<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > { struct visitor: boost::static_visitor<std::size_t> { template <typename Geometry> inline std::size_t operator()(Geometry const& geometry) const { return num_interior_rings<Geometry>::apply(geometry); } }; static inline std::size_t apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry) { return boost::apply_visitor(visitor(), geometry); } }; } // namespace resolve_variant /*! \brief \brief_calc{number of interior rings} \ingroup num_interior_rings \details \details_calc{num_interior_rings, number of interior rings}. \tparam Geometry \tparam_geometry \param geometry \param_geometry \return \return_calc{number of interior rings} \qbk{[include reference/algorithms/num_interior_rings.qbk]} \note Defined by OGC as "numInteriorRing". To be consistent with "numPoints" letter "s" is appended */ template <typename Geometry> inline std::size_t num_interior_rings(Geometry const& geometry) { return resolve_variant::num_interior_rings<Geometry>::apply(geometry); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_NUM_INTERIOR_RINGS_HPP within.hpp 0000644 00000002041 15125631657 0006567 0 ustar 00 // Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // This file was modified by Oracle on 2013, 2014, 2017. // Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP #define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP #include <boost/geometry/algorithms/detail/within/interface.hpp> #include <boost/geometry/algorithms/detail/within/implementation.hpp> #endif // BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP
| ver. 1.6 |
Github
|
.
| PHP 8.2.30 | ??????????? ?????????: 0.65 |
proxy
|
phpinfo
|
???????????