update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -4,9 +4,9 @@
// 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.
// This file was modified by Oracle on 2014-2023.
// Modifications copyright (c) 2014-2023, 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
@@ -21,20 +21,19 @@
#define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
#include <boost/range.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.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/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // for backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/variant.hpp>
#include <boost/geometry/util/range.hpp>
@@ -46,20 +45,20 @@ namespace boost { namespace geometry
namespace detail { namespace append
{
template <typename Geometry, typename Point>
struct append_no_action
{
template <typename Geometry, typename Point>
static inline void apply(Geometry& , Point const& ,
int = 0, int = 0)
signed_size_type = -1, signed_size_type = 0)
{
}
};
template <typename Geometry, typename Point>
struct append_point
struct to_range_point
{
template <typename Geometry, typename Point>
static inline void apply(Geometry& geometry, Point const& point,
int = 0, int = 0)
signed_size_type = -1, signed_size_type = 0)
{
typename geometry::point_type<Geometry>::type copy;
geometry::detail::conversion::convert_point_to_point(point, copy);
@@ -68,287 +67,191 @@ struct append_point
};
template <typename Geometry, typename Range>
struct append_range
struct to_range_range
{
typedef typename boost::range_value<Range>::type point_type;
template <typename Geometry, typename Range>
static inline void apply(Geometry& geometry, Range const& range,
int = 0, int = 0)
signed_size_type = -1, signed_size_type = 0)
{
for (typename boost::range_iterator<Range const>::type
it = boost::begin(range);
it != boost::end(range);
++it)
using point_type = typename boost::range_value<Range>::type;
auto const end = boost::end(range);
for (auto it = boost::begin(range); it != end; ++it)
{
append_point<Geometry, point_type>::apply(geometry, *it);
to_range_point::apply<Geometry, point_type>(geometry, *it);
}
}
};
template <typename Polygon, typename Point>
struct point_to_polygon
struct to_polygon_point
{
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;
template <typename Polygon, typename Point>
static inline void apply(Polygon& polygon, Point const& point,
int ring_index, int = 0)
signed_size_type ring_index, signed_size_type = 0)
{
using ring_type = typename ring_type<Polygon>::type;
if (ring_index == -1)
{
exterior_ring_type ext_ring = exterior_ring(polygon);
append_point<ring_type, Point>::apply(
ext_ring, point);
auto&& ext_ring = exterior_ring(polygon);
to_range_point::apply<ring_type, Point>(ext_ring, point);
}
else if (ring_index < int(num_interior_rings(polygon)))
else if (ring_index < signed_size_type(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);
auto&& int_rings = interior_rings(polygon);
to_range_point::apply<ring_type, Point>(range::at(int_rings, ring_index), point);
}
}
};
template <typename Polygon, typename Range>
struct range_to_polygon
struct to_polygon_range
{
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;
template <typename Polygon, typename Range>
static inline void apply(Polygon& polygon, Range const& range,
int ring_index, int = 0)
signed_size_type ring_index, signed_size_type = 0)
{
using ring_type = typename ring_type<Polygon>::type;
using exterior_ring_type = typename ring_return_type<Polygon>::type;
using interior_ring_range_type = typename interior_return_type<Polygon>::type;
if (ring_index == -1)
{
exterior_ring_type ext_ring = exterior_ring(polygon);
append_range<ring_type, Range>::apply(
ext_ring, range);
to_range_range::apply<ring_type, Range>(ext_ring, range);
}
else if (ring_index < int(num_interior_rings(polygon)))
else if (ring_index < signed_size_type(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);
to_range_range::apply<ring_type, Range>(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
template <typename Policy>
struct to_multigeometry
{
template <typename MultiGeometry, typename RangeOrPoint>
static inline void apply(MultiGeometry& multigeometry,
RangeOrPoint const& range_or_point,
int ring_index, int multi_index)
signed_size_type ring_index, signed_size_type multi_index)
{
dispatch::append
Policy::template apply
<
typename boost::range_value<MultiGeometry>::type,
RangeOrPoint
>::apply(range::at(multigeometry, multi_index), range_or_point, ring_index);
>(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 RangeOrPoint,
typename Tag = typename geometry::tag<Geometry>::type,
typename OtherTag = typename geometry::tag<RangeOrPoint>::type
>
struct append
: detail::append::append_no_action
{};
template <typename Geometry, typename Point>
struct append_point<multi_point_tag, Geometry, Point>
: detail::append::append_point<Geometry, Point>
struct append<Geometry, Point, linestring_tag, point_tag>
: detail::append::to_range_point
{};
template <typename Geometry, typename Range>
struct append_range<multi_point_tag, Geometry, Range>
: detail::append::append_range<Geometry, Range>
template <typename Geometry, typename Point>
struct append<Geometry, Point, ring_tag, point_tag>
: detail::append::to_range_point
{};
template <typename MultiGeometry, typename RangeOrPoint>
struct append_point<multi_linestring_tag, MultiGeometry, RangeOrPoint>
: detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
template <typename Polygon, typename Point>
struct append<Polygon, Point, polygon_tag, point_tag>
: detail::append::to_polygon_point
{};
template <typename MultiGeometry, typename RangeOrPoint>
struct append_range<multi_linestring_tag, MultiGeometry, RangeOrPoint>
: detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
template <typename Geometry, typename Range, typename RangeTag>
struct append<Geometry, Range, linestring_tag, RangeTag>
: detail::append::to_range_range
{};
template <typename MultiGeometry, typename RangeOrPoint>
struct append_point<multi_polygon_tag, MultiGeometry, RangeOrPoint>
: detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
template <typename Geometry, typename Range, typename RangeTag>
struct append<Geometry, Range, ring_tag, RangeTag>
: detail::append::to_range_range
{};
template <typename MultiGeometry, typename RangeOrPoint>
struct append_range<multi_polygon_tag, MultiGeometry, RangeOrPoint>
: detail::append::append_to_multigeometry<MultiGeometry, RangeOrPoint>
template <typename Polygon, typename Range, typename RangeTag>
struct append<Polygon, Range, polygon_tag, RangeTag>
: detail::append::to_polygon_range
{};
} // namespace splitted_dispatch
template <typename Geometry, typename Point>
struct append<Geometry, Point, multi_point_tag, point_tag>
: detail::append::to_range_point
{};
template <typename Geometry, typename Range, typename RangeTag>
struct append<Geometry, Range, multi_point_tag, RangeTag>
: detail::append::to_range_range
{};
template <typename MultiGeometry, typename Point>
struct append<MultiGeometry, Point, multi_linestring_tag, point_tag>
: detail::append::to_multigeometry<detail::append::to_range_point>
{};
template <typename MultiGeometry, typename Range, typename RangeTag>
struct append<MultiGeometry, Range, multi_linestring_tag, RangeTag>
: detail::append::to_multigeometry<detail::append::to_range_range>
{};
template <typename MultiGeometry, typename Point>
struct append<MultiGeometry, Point, multi_polygon_tag, point_tag>
: detail::append::to_multigeometry<detail::append::to_polygon_point>
{};
template <typename MultiGeometry, typename Range, typename RangeTag>
struct append<MultiGeometry, Range, multi_polygon_tag, RangeTag>
: detail::append::to_multigeometry<detail::append::to_polygon_range>
{};
template <typename Geometry, typename RangeOrPoint, typename OtherTag>
struct append<Geometry, RangeOrPoint, dynamic_geometry_tag, OtherTag>
{
static inline void apply(Geometry& geometry,
RangeOrPoint const& range_or_point,
signed_size_type ring_index, signed_size_type multi_index)
{
traits::visit<Geometry>::apply([&](auto & g)
{
append
<
std::remove_reference_t<decltype(g)>, RangeOrPoint
>::apply(g, range_or_point, ring_index, multi_index);
}, geometry);
}
};
// TODO: It's unclear how append should work for GeometryCollection because
// it can hold multiple different geometries.
} // 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
@@ -365,10 +268,14 @@ struct append<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
*/
template <typename Geometry, typename RangeOrPoint>
inline void append(Geometry& geometry, RangeOrPoint const& range_or_point,
int ring_index = -1, int multi_index = 0)
signed_size_type ring_index = -1, signed_size_type multi_index = 0)
{
resolve_variant::append<Geometry>
::apply(geometry, range_or_point, ring_index, multi_index);
concepts::check<Geometry>();
dispatch::append
<
Geometry, RangeOrPoint
>::apply(geometry, range_or_point, ring_index, multi_index);
}

View File

@@ -3,10 +3,11 @@
// 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.
// Copyright (c) 2017-2022 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2023.
// Modifications copyright (c) 2017-2023 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -19,14 +20,11 @@
#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/functions.hpp>
#include <boost/range/metafunctions.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.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/exterior_ring.hpp>
@@ -35,25 +33,28 @@
#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/core/visit.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/detail/visit.hpp>
#include <boost/geometry/strategies/area.hpp>
#include <boost/geometry/strategies/area_result.hpp>
#include <boost/geometry/strategies/default_area_result.hpp>
#include <boost/geometry/algorithms/area_result.hpp>
#include <boost/geometry/algorithms/default_area_result.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/area/services.hpp>
#include <boost/geometry/strategies/area/cartesian.hpp>
#include <boost/geometry/strategies/area/geographic.hpp>
#include <boost/geometry/strategies/area/spherical.hpp>
#include <boost/geometry/strategies/concepts/area_concept.hpp>
#include <boost/geometry/strategies/default_strategy.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>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
@@ -66,61 +67,48 @@ 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&)
template <typename Box, typename Strategies>
static inline auto
apply(Box const& box, Strategies const& strategies)
{
// 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));
return strategies.area(box).apply(box);
}
};
template
<
iterate_direction Direction,
closure_selector Closure
>
struct ring_area
{
template <typename Ring, typename Strategy>
static inline typename area_result<Ring, Strategy>::type
apply(Ring const& ring, Strategy const& strategy)
template <typename Ring, typename Strategies>
static inline typename area_result<Ring, Strategies>::type
apply(Ring const& ring, Strategies const& strategies)
{
BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy<Ring, Strategy>) );
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(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)
if (boost::size(ring) < detail::minimum_ring_size<Ring>::value)
{
return typename area_result<Ring, Strategy>::type();
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;
detail::closed_clockwise_view<Ring const> const view(ring);
auto it = boost::begin(view);
auto const end = boost::end(view);
rview_type rview(ring);
view_type view(rview);
typename Strategy::template state<Ring> state;
iterator_type it = boost::begin(view);
iterator_type end = boost::end(view);
strategy_type const strategy = strategies.area(ring);
typename strategy_type::template state<Ring> state;
for (iterator_type previous = it++;
it != end;
++previous, ++it)
for (auto previous = it++; it != end; ++previous, ++it)
{
strategy.apply(*previous, *it, state);
}
@@ -167,10 +155,6 @@ 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
>
{};
@@ -181,13 +165,10 @@ struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
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
>
return calculate_polygon_sum::apply
<
typename area_result<Polygon, Strategy>::type,
detail::area::ring_area
>(polygon, strategy);
}
};
@@ -216,7 +197,11 @@ struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
namespace resolve_strategy
{
template <typename Strategy>
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct area
{
template <typename Geometry>
@@ -227,16 +212,30 @@ struct area
}
};
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>
struct area<default_strategy, false>
{
template <typename Geometry>
static inline typename area_result<Geometry>::type
apply(Geometry const& geometry, default_strategy)
{
typedef typename strategy::area::services::default_strategy
typedef typename strategies::area::services::default_strategy
<
typename cs_tag<Geometry>::type
Geometry
>::type strategy_type;
return dispatch::area<Geometry>::apply(geometry, strategy_type());
@@ -247,10 +246,10 @@ struct area<default_strategy>
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type>
struct area
{
template <typename Strategy>
@@ -261,37 +260,40 @@ struct area
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct area<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct area<Geometry, dynamic_geometry_tag>
{
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>
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
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
typename area_result<Geometry, Strategy>::type result = 0;
traits::visit<Geometry>::apply([&](auto const& g)
{
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);
result = area<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
}, geometry);
return result;
}
};
} // namespace resolve_variant
template <typename Geometry>
struct area<Geometry, geometry_collection_tag>
{
template <typename Strategy>
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
typename area_result<Geometry, Strategy>::type result = 0;
detail::visit_breadth_first([&](auto const& g)
{
result += area<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
return true;
}, geometry);
return result;
}
};
} // namespace resolve_dynamic
/*!
@@ -323,7 +325,7 @@ area(Geometry const& geometry)
// detail::throw_on_empty_input(geometry);
return resolve_variant::area<Geometry>::apply(geometry, default_strategy());
return resolve_dynamic::area<Geometry>::apply(geometry, default_strategy());
}
/*!
@@ -359,7 +361,7 @@ area(Geometry const& geometry, Strategy const& strategy)
// detail::throw_on_empty_input(geometry);
return resolve_variant::area<Geometry>::apply(geometry, strategy);
return resolve_dynamic::area<Geometry>::apply(geometry, strategy);
}

View File

@@ -0,0 +1,141 @@
// Boost.Geometry
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2020-2023.
// Modifications copyright (c) 2020-2023 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_AREA_RESULT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_AREA_RESULT_HPP
#include <type_traits>
#include <boost/geometry/algorithms/detail/select_geometry_type.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/strategies/area/services.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/util/select_most_precise.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>
struct default_area_result
: area_result
<
Geometry,
typename geometry::strategies::area::services::default_strategy
<
Geometry
>::type
>
{};
template <typename Curr, typename Next>
struct more_precise_coordinate_type
: std::is_same
<
typename geometry::coordinate_type<Curr>::type,
typename geometry::select_most_precise
<
typename geometry::coordinate_type<Curr>::type,
typename geometry::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
<
typename detail::select_geometry_type
<
Geometry,
detail::area::more_precise_coordinate_type
>::type,
Strategy
>
{};
template <typename Geometry>
struct area_result<Geometry, default_strategy>
: detail::area::default_area_result
<
typename detail::select_geometry_type
<
Geometry,
detail::area::more_precise_default_area_result
>::type
>
{};
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_AREA_RESULT_HPP

View File

@@ -5,6 +5,11 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2020-2023.
// Modifications copyright (c) 2020-2023 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,35 +20,21 @@
#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/mpl/assert.hpp>
#include <boost/mpl/if.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/append.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.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/tags.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
namespace boost { namespace geometry
{
@@ -230,40 +221,36 @@ struct assign
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_MPL_ASSERT_MSG
(
(same_point_order),
ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_POINT_ORDER,
(types<Geometry1, Geometry2>)
);
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_MPL_ASSERT_MSG
(
(same_closure),
ASSIGN_IS_NOT_SUPPORTED_FOR_DIFFERENT_CLOSURE,
(types<Geometry1, Geometry2>)
);
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
{
@@ -275,7 +262,7 @@ struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
(geometry1, m_geometry2);
}
};
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1,
Geometry2 const& geometry2)
@@ -283,19 +270,19 @@ struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, 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
{
@@ -307,7 +294,7 @@ struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
(m_geometry1, geometry2);
}
};
static inline void
apply(Geometry1& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
@@ -315,8 +302,8 @@ struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
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)> >
{
@@ -335,7 +322,7 @@ struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM
(geometry1, geometry2);
}
};
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
@@ -343,9 +330,9 @@ struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM
return boost::apply_visitor(visitor(), geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief Assigns one geometry to another geometry

View File

@@ -0,0 +1,221 @@
// Boost.Geometry
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014-2023.
// Modifications copyright (c) 2014-2023, 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_AZIMUTH_HPP
#define BOOST_GEOMETRY_ALGORITHMS_AZIMUTH_HPP
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/azimuth/cartesian.hpp>
#include <boost/geometry/strategies/azimuth/geographic.hpp>
#include <boost/geometry/strategies/azimuth/spherical.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
} // namespace detail
#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 azimuth : not_implemented<Tag1, Tag2>
{};
template <typename Point1, typename Point2>
struct azimuth<Point1, Point2, point_tag, point_tag>
{
template <typename Strategy>
static auto apply(Point1 const& p1, Point2 const& p2, Strategy const& strategy)
{
typedef typename decltype(strategy.azimuth())::template result_type
<
typename coordinate_type<Point1>::type,
typename coordinate_type<Point2>::type
>::type calc_t;
calc_t result = 0;
calc_t const x1 = geometry::get_as_radian<0>(p1);
calc_t const y1 = geometry::get_as_radian<1>(p1);
calc_t const x2 = geometry::get_as_radian<0>(p2);
calc_t const y2 = geometry::get_as_radian<1>(p2);
strategy.azimuth().apply(x1, y1, x2, y2, result);
// NOTE: It is not clear which units we should use for the result.
// For now radians are always returned but a user could expect
// e.g. something like this:
/*
bool const both_degree = std::is_same
<
typename detail::cs_angular_units<Point1>::type,
geometry::degree
>::value
&& std::is_same
<
typename detail::cs_angular_units<Point2>::type,
geometry::degree
>::value;
if (both_degree)
{
result *= math::r2d<calc_t>();
}
*/
return result;
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct azimuth
{
template <typename P1, typename P2>
static auto apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
{
return dispatch::azimuth<P1, P2>::apply(p1, p2, strategy);
}
};
template <typename Strategy>
struct azimuth<Strategy, false>
{
template <typename P1, typename P2>
static auto apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
{
using strategies::azimuth::services::strategy_converter;
return dispatch::azimuth
<
P1, P2
>::apply(p1, p2, strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct azimuth<default_strategy, false>
{
template <typename P1, typename P2>
static auto apply(P1 const& p1, P2 const& p2, default_strategy)
{
typedef typename strategies::azimuth::services::default_strategy
<
P1, P2
>::type strategy_type;
return dispatch::azimuth<P1, P2>::apply(p1, p2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
{
} // namespace resolve_variant
/*!
\brief Calculate azimuth of a segment defined by a pair of points.
\ingroup azimuth
\tparam Point1 Type of the first point of a segment.
\tparam Point2 Type of the second point of a segment.
\param point1 First point of a segment.
\param point2 Second point of a segment.
\return Azimuth in radians.
\qbk{[include reference/algorithms/azimuth.qbk]}
\qbk{
[heading Example]
[azimuth]
[azimuth_output]
}
*/
template <typename Point1, typename Point2>
inline auto azimuth(Point1 const& point1, Point2 const& point2)
{
concepts::check<Point1 const>();
concepts::check<Point2 const>();
return resolve_strategy::azimuth
<
default_strategy
>::apply(point1, point2, default_strategy());
}
/*!
\brief Calculate azimuth of a segment defined by a pair of points.
\ingroup azimuth
\tparam Point1 Type of the first point of a segment.
\tparam Point2 Type of the second point of a segment.
\tparam Strategy Type of an umbrella strategy defining azimuth strategy.
\param point1 First point of a segment.
\param point2 Second point of a segment.
\param strategy Umbrella strategy defining azimuth strategy.
\return Azimuth in radians.
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/azimuth.qbk]}
\qbk{
[heading Example]
[azimuth_strategy]
[azimuth_strategy_output]
}
*/
template <typename Point1, typename Point2, typename Strategy>
inline auto azimuth(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
{
concepts::check<Point1 const>();
concepts::check<Point2 const>();
return resolve_strategy::azimuth<Strategy>::apply(point1, point2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_AZIMUTH_HPP

View File

@@ -4,8 +4,8 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2022.
// Modifications copyright (c) 2017-2022 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
@@ -18,245 +18,7 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.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>::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);
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
#include <boost/geometry/algorithms/detail/buffer/interface.hpp>
#include <boost/geometry/algorithms/detail/buffer/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP

View File

@@ -5,11 +5,11 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// 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
// This file was modified by Oracle on 2014-2023.
// Modifications copyright (c) 2014-2023 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.
@@ -25,41 +25,39 @@
#include <cstddef>
#include <boost/core/ignore_unused.hpp>
#include <boost/range.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/core/visit.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#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/centroid/cartesian.hpp>
#include <boost/geometry/strategies/centroid/geographic.hpp>
#include <boost/geometry/strategies/centroid/spherical.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/strategies/detail.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/detail/centroid/translating_transformer.hpp>
#include <boost/geometry/views/closeable_view.hpp>
namespace boost { namespace geometry
@@ -116,56 +114,24 @@ struct centroid_point
}
};
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
typedef typename select_coordinate_type
<
Indexed, Point
>::apply(indexed, centroid);
>::type coordinate_type;
detail::for_each_dimension<Indexed>([&](auto dimension)
{
coordinate_type const c1 = get<min_corner, dimension>(indexed);
coordinate_type const c2 = get<max_corner, dimension>(indexed);
coordinate_type const two = 2;
set<dimension>(centroid, (c1 + c2) / two);
});
}
};
@@ -201,25 +167,19 @@ inline bool range_ok(Range const& range, Point& centroid)
/*!
\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>
template<typename Ring, typename PointTransformer, typename Strategy, typename State>
static inline void apply(Ring const& ring,
PointTransformer const& transformer,
Strategy const& strategy,
typename Strategy::state_type& state)
State& 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);
detail::closed_view<Ring const> const view(ring);
auto it = boost::begin(view);
auto const end = boost::end(view);
if (it != end)
{
@@ -231,6 +191,7 @@ struct centroid_range_state
typename PointTransformer::result_type
pt = transformer.apply(*it);
using point_type = typename geometry::point_type<Ring const>::type;
strategy.apply(static_cast<point_type const&>(previous_pt),
static_cast<point_type const&>(pt),
state);
@@ -241,7 +202,6 @@ struct centroid_range_state
}
};
template <closure_selector Closure>
struct centroid_range
{
template<typename Range, typename Point, typename Strategy>
@@ -252,11 +212,15 @@ struct centroid_range
{
// prepare translation transformer
translating_transformer<Range> transformer(*boost::begin(range));
typename Strategy::state_type state;
centroid_range_state<Closure>::apply(range, transformer,
strategy, state);
typename Strategy::template state_type
<
typename geometry::point_type<Range>::type,
Point
>::type state;
centroid_range_state::apply(range, transformer, strategy, state);
if ( strategy.result(state, centroid) )
{
// translate the result back
@@ -277,24 +241,19 @@ struct centroid_range
*/
struct centroid_polygon_state
{
template<typename Polygon, typename PointTransformer, typename Strategy>
template<typename Polygon, typename PointTransformer, typename Strategy, typename State>
static inline void apply(Polygon const& poly,
PointTransformer const& transformer,
Strategy const& strategy,
typename Strategy::state_type& state)
State& state)
{
typedef typename ring_type<Polygon>::type ring_type;
typedef centroid_range_state<geometry::closure<ring_type>::value> per_ring;
centroid_range_state::apply(exterior_ring(poly), transformer, strategy, state);
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)
auto const& rings = interior_rings(poly);
auto const end = boost::end(rings);
for (auto it = boost::begin(rings); it != end; ++it)
{
per_ring::apply(*it, transformer, strategy, state);
centroid_range_state::apply(*it, transformer, strategy, state);
}
}
};
@@ -310,10 +269,15 @@ struct centroid_polygon
// prepare translation transformer
translating_transformer<Polygon>
transformer(*boost::begin(exterior_ring(poly)));
typename Strategy::state_type state;
typename Strategy::template state_type
<
typename geometry::point_type<Polygon>::type,
Point
>::type state;
centroid_polygon_state::apply(poly, transformer, strategy, state);
if ( strategy.result(state, centroid) )
{
// translate the result back
@@ -333,11 +297,11 @@ struct centroid_polygon
*/
struct centroid_multi_point_state
{
template <typename Point, typename PointTransformer, typename Strategy>
template <typename Point, typename PointTransformer, typename Strategy, typename State>
static inline void apply(Point const& point,
PointTransformer const& transformer,
Strategy const& strategy,
typename Strategy::state_type& state)
State& state)
{
boost::ignore_unused(strategy);
strategy.apply(static_cast<Point const&>(transformer.apply(point)),
@@ -374,23 +338,24 @@ struct centroid_multi
// prepare translation transformer
translating_transformer<Multi> transformer(multi);
typename Strategy::state_type state;
typename Strategy::template state_type
<
typename geometry::point_type<Multi>::type,
Point
>::type state;
for (typename boost::range_iterator<Multi const>::type
it = boost::begin(multi);
it != boost::end(multi);
++it)
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
Policy::apply(*it, transformer, strategy, state);
}
if ( strategy.result(state, centroid) )
if (strategy.result(state, centroid))
{
// translate the result back
transformer.apply_reverse(centroid);
return true;
}
return false;
}
};
@@ -399,18 +364,30 @@ struct centroid_multi
template <typename Algorithm>
struct centroid_linear_areal
{
template <typename Geometry, typename Point, typename Strategy>
template <typename Geometry, typename Point, typename Strategies>
static inline void apply(Geometry const& geom,
Point& centroid,
Strategy const& strategy)
Strategies const& strategies)
{
if ( ! Algorithm::apply(geom, centroid, strategy) )
if ( ! Algorithm::apply(geom, centroid, strategies.centroid(geom)) )
{
geometry::point_on_border(centroid, geom);
}
}
};
template <typename Algorithm>
struct centroid_pointlike
{
template <typename Geometry, typename Point, typename Strategies>
static inline void apply(Geometry const& geom,
Point& centroid,
Strategies const& strategies)
{
Algorithm::apply(geom, centroid, strategies.centroid(geom));
}
};
}} // namespace detail::centroid
#endif // DOXYGEN_NO_DETAIL
@@ -447,7 +424,7 @@ template <typename Ring>
struct centroid<Ring, ring_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_range<geometry::closure<Ring>::value>
detail::centroid::centroid_range
>
{};
@@ -455,7 +432,7 @@ template <typename Linestring>
struct centroid<Linestring, linestring_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_range<closed>
detail::centroid::centroid_range
>
{};
@@ -473,7 +450,7 @@ struct centroid<MultiLinestring, multi_linestring_tag>
<
detail::centroid::centroid_multi
<
detail::centroid::centroid_range_state<closed>
detail::centroid::centroid_range_state
>
>
{};
@@ -491,9 +468,12 @@ struct centroid<MultiPolygon, multi_polygon_tag>
template <typename MultiPoint>
struct centroid<MultiPoint, multi_point_tag>
: detail::centroid::centroid_multi
: detail::centroid::centroid_pointlike
<
detail::centroid::centroid_multi_point_state
detail::centroid::centroid_multi
<
detail::centroid::centroid_multi_point_state
>
>
{};
@@ -504,84 +484,81 @@ struct centroid<MultiPoint, multi_point_tag>
namespace resolve_strategy {
template <typename Geometry>
template
<
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct centroid
{
template <typename Point, typename Strategy>
template <typename Geometry, typename Point>
static inline void apply(Geometry const& geometry, Point& out, Strategies const& strategies)
{
dispatch::centroid<Geometry>::apply(geometry, out, strategies);
}
};
template <typename Strategy>
struct centroid<Strategy, false>
{
template <typename Geometry, typename Point>
static inline void apply(Geometry const& geometry, Point& out, Strategy const& strategy)
{
dispatch::centroid<Geometry>::apply(geometry, out, strategy);
using strategies::centroid::services::strategy_converter;
dispatch::centroid
<
Geometry
>::apply(geometry, out, strategy_converter<Strategy>::get(strategy));
}
};
template <typename Point>
template <>
struct centroid<default_strategy, false>
{
template <typename Geometry, 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;
typedef typename strategies::centroid::services::default_strategy
<
Geometry
>::type strategies_type;
dispatch::centroid<Geometry>::apply(geometry, out, strategy_type());
dispatch::centroid<Geometry>::apply(geometry, out, strategies_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
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);
resolve_strategy::centroid<Strategy>::apply(geometry, out, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct centroid<Geometry, dynamic_geometry_tag>
{
template <typename Point, typename Strategy>
struct visitor: boost::static_visitor<void>
static inline void apply(Geometry const& geometry,
Point& out,
Strategy const& strategy)
{
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
traits::visit<Geometry>::apply([&](auto const& g)
{
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);
centroid<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy);
}, geometry);
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
@@ -602,10 +579,9 @@ struct centroid<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
*/
template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c,
Strategy const& strategy)
inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy)
{
resolve_variant::centroid<Geometry>::apply(geometry, c, strategy);
resolve_dynamic::centroid<Geometry>::apply(geometry, c, strategy);
}

View File

@@ -4,6 +4,11 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2020-2023.
// Modifications copyright (c) 2020-2023, 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -15,19 +20,16 @@
#define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
#include <boost/type_traits/remove_const.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <type_traits>
#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/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // for backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -54,14 +56,14 @@ struct polygon_clear
{
traits::clear
<
typename boost::remove_reference
typename std::remove_reference
<
typename traits::interior_mutable_type<Polygon>::type
>::type
>::apply(interior_rings(polygon));
traits::clear
<
typename boost::remove_reference
typename std::remove_reference
<
typename traits::ring_mutable_type<Polygon>::type
>::type
@@ -133,40 +135,31 @@ struct clear<Geometry, multi_tag>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
template <typename Geometry>
struct clear<Geometry, dynamic_geometry_tag>
{
static void apply(Geometry& geometry)
{
traits::visit<Geometry>::apply([](auto & g)
{
clear<std::remove_reference_t<decltype(g)>>::apply(g);
}, geometry);
}
};
namespace resolve_variant {
template <typename Geometry>
struct clear
struct clear<Geometry, geometry_collection_tag>
{
static inline void apply(Geometry& geometry)
static void apply(Geometry& geometry)
{
dispatch::clear<Geometry>::apply(geometry);
traits::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
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
@@ -187,7 +180,7 @@ inline void clear(Geometry& geometry)
{
concepts::check<Geometry>();
resolve_variant::clear<Geometry>::apply(geometry);
dispatch::clear<Geometry>::apply(geometry);
}

View File

@@ -0,0 +1,16 @@
// Boost.Geometry
// Copyright (c) 2021, 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_CLOSEST_POINTS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CLOSEST_POINTS_HPP
#include <boost/geometry/algorithms/detail/closest_points/interface.hpp>
#include <boost/geometry/algorithms/detail/closest_points/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_CLOSEST_POINTS_HPP

View File

@@ -5,8 +5,9 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017, Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2023.
// Modifications copyright (c) 2017-2023, 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -21,38 +22,33 @@
#include <cstddef>
#include <type_traits>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/variant/apply_visitor.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/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/for_each.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/algorithms/not_implemented.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>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
{
@@ -128,7 +124,7 @@ struct segment_to_range
{
traits::resize<Range>::apply(range, 2);
typename boost::range_iterator<Range>::type it = boost::begin(range);
auto it = boost::begin(range);
assign_point_from_index<0>(segment, *it);
++it;
@@ -144,17 +140,6 @@ template
>
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>
@@ -163,7 +148,7 @@ struct range_to_range
geometry::detail::conversion::convert_point_to_point(point1, point2);
}
};
static inline void apply(Range1 const& source, Range2& destination)
{
apply(source, destination, default_policy());
@@ -175,11 +160,16 @@ struct range_to_range
{
geometry::clear(destination);
rview_type rview(source);
using view_type = detail::closed_clockwise_view
<
Range1 const,
geometry::closure<Range1>::value,
Reverse ? counterclockwise : clockwise
>;
// We consider input always as closed, and skip last
// point for open output.
view_type view(rview);
view_type const view(source);
typedef typename boost::range_size<Range1>::type size_type;
size_type n = boost::size(view);
@@ -192,8 +182,7 @@ struct range_to_range
// but ok, sice below it == end()
size_type i = 0;
for (typename boost::range_iterator<view_type const>::type it
= boost::begin(view);
for (auto it = boost::begin(view);
it != boost::end(view) && i < n;
++it, ++i)
{
@@ -227,21 +216,17 @@ struct polygon_to_polygon
// Container should be resizeable
traits::resize
<
typename boost::remove_reference
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);
auto const& rings_source = interior_rings(source);
auto&& 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);
auto it_source = boost::begin(rings_source);
auto it_dest = boost::begin(rings_dest);
for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest)
{
@@ -269,10 +254,8 @@ struct multi_to_multi: private Policy
{
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);
auto it1 = boost::begin(multi1);
auto it2 = boost::begin(multi2);
for (; it1 != boost::end(multi1); ++it1, ++it2)
{
@@ -290,16 +273,25 @@ struct multi_to_multi: private Policy
namespace dispatch
{
// TODO: We could use std::is_assignable instead of std::is_same.
// Then we should rather check ! std::is_array<Geometry2>::value
// which is Destination.
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 = boost::is_same<Geometry1, Geometry2>::value
&& !boost::is_array<Geometry1>::value
bool UseAssignment = std::is_same<Geometry1, Geometry2>::value
&& !std::is_array<Geometry1>::value
>
struct convert: not_implemented<Tag1, Tag2, boost::mpl::int_<DimensionCount> >
struct convert
: not_implemented
<
Tag1, Tag2,
std::integral_constant<std::size_t, DimensionCount>
>
{};
@@ -457,7 +449,7 @@ struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
// 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 boost::is_same again
// 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>

View File

@@ -4,11 +4,12 @@
// 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.
// This file was modified by Oracle on 2014, 2015, 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 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.
@@ -20,356 +21,7 @@
#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
#include <boost/geometry/algorithms/detail/convex_hull/interface.hpp>
#include <boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP

View File

@@ -5,8 +5,9 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2023.
// Modifications copyright (c) 2017-2023 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -21,33 +22,31 @@
#include <algorithm>
#include <cstddef>
#include <functional>
#include <boost/mpl/assert.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/remove_reference.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/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/correct_closure.hpp>
#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/util/order_as_direction.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/area/cartesian.hpp>
#include <boost/geometry/strategies/area/geographic.hpp>
#include <boost/geometry/strategies/area/spherical.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/util/algorithm.hpp>
namespace boost { namespace geometry
{
@@ -62,92 +61,56 @@ namespace boost { namespace geometry
namespace detail { namespace correct
{
template <typename Geometry>
struct correct_nop
{
template <typename Strategy>
template <typename Geometry, 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>
template <typename Box, typename Strategy>
static inline void apply(Box& box, Strategy const& )
{
using coordinate_type = typename geometry::coordinate_type<Box>::type;
// 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);
detail::for_each_dimension<Box>([&](auto dimension)
{
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);
}
});
}
};
// Close a ring, if not closed
template <typename Ring, template <typename> class Predicate>
template <typename Predicate = std::less<>>
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>
template <typename Ring, 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);
detail::correct_closure::close_or_open_ring::apply(r);
// NOTE: calculate_point_order should probably be used here instead.
// 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, strategy), zero))
using area_t = typename area_result<Ring, Strategy>::type;
area_t const zero = 0;
if (Predicate()(detail::area::ring_area::apply(r, strategy), zero))
{
std::reverse(boost::begin(r), boost::end(r));
}
@@ -156,30 +119,18 @@ struct correct_ring
// 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>
template <typename Polygon, typename Strategy>
static inline void apply(Polygon& poly, Strategy const& strategy)
{
correct_ring
<
ring_type,
std::less
>::apply(exterior_ring(poly), strategy);
correct_ring<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)
auto&& rings = interior_rings(poly);
auto const end = boost::end(rings);
for (auto it = boost::begin(rings); it != end; ++it)
{
correct_ring
<
ring_type,
std::greater
>::apply(*it, strategy);
correct_ring<std::greater<>>::apply(*it, strategy);
}
}
};
@@ -199,62 +150,51 @@ struct correct: not_implemented<Tag>
template <typename Point>
struct correct<Point, point_tag>
: detail::correct::correct_nop<Point>
: detail::correct::correct_nop
{};
template <typename LineString>
struct correct<LineString, linestring_tag>
: detail::correct::correct_nop<LineString>
: detail::correct::correct_nop
{};
template <typename Segment>
struct correct<Segment, segment_tag>
: detail::correct::correct_nop<Segment>
: detail::correct::correct_nop
{};
template <typename Box>
struct correct<Box, box_tag>
: detail::correct::correct_box<Box>
: detail::correct::correct_box
{};
template <typename Ring>
struct correct<Ring, ring_tag>
: detail::correct::correct_ring
<
Ring,
std::less
>
: detail::correct::correct_ring<>
{};
template <typename Polygon>
struct correct<Polygon, polygon_tag>
: detail::correct::correct_polygon<Polygon>
: detail::correct::correct_polygon
{};
template <typename MultiPoint>
struct correct<MultiPoint, multi_point_tag>
: detail::correct::correct_nop<MultiPoint>
: detail::correct::correct_nop
{};
template <typename MultiLineString>
struct correct<MultiLineString, multi_linestring_tag>
: detail::correct::correct_nop<MultiLineString>
: detail::correct::correct_nop
{};
template <typename Geometry>
struct correct<Geometry, multi_polygon_tag>
: detail::multi_modify
<
Geometry,
detail::correct::correct_polygon
<
typename boost::range_value<Geometry>::type
>
>
: detail::multi_modify<detail::correct::correct_polygon>
{};
@@ -262,45 +202,96 @@ struct correct<Geometry, multi_polygon_tag>
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant {
namespace resolve_strategy
{
template <typename Geometry>
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct correct
{
template <typename Geometry>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
dispatch::correct<Geometry>::apply(geometry, strategy);
}
};
template <typename Strategy>
struct correct<Strategy, false>
{
template <typename Geometry>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
// NOTE: calculate_point_order strategy should probably be used here instead.
using geometry::strategies::area::services::strategy_converter;
dispatch::correct<Geometry>::apply(geometry, strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct correct<default_strategy, false>
{
template <typename Geometry>
static inline void apply(Geometry& geometry, default_strategy const& )
{
// NOTE: calculate_point_order strategy should probably be used here instead.
using strategy_type = typename strategies::area::services::default_strategy
<
Geometry
>::type;
dispatch::correct<Geometry>::apply(geometry, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct correct
{
template <typename Strategy>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
dispatch::correct<Geometry>::apply(geometry, strategy);
concepts::check<Geometry>();
resolve_strategy::correct<Strategy>::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct correct<Geometry, dynamic_geometry_tag>
{
template <typename Strategy>
struct visitor: boost::static_visitor<void>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
Strategy const& m_strategy;
visitor(Strategy const& strategy): m_strategy(strategy) {}
template <typename Geometry>
void operator()(Geometry& geometry) const
traits::visit<Geometry>::apply([&](auto & g)
{
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);
correct<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
}, geometry);
}
};
} // namespace resolve_variant
template <typename Geometry>
struct correct<Geometry, geometry_collection_tag>
{
template <typename Strategy>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
detail::visit_breadth_first([&](auto & g)
{
correct<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
return true;
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
@@ -318,14 +309,7 @@ struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
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());
resolve_dynamic::correct<Geometry>::apply(geometry, default_strategy());
}
/*!
@@ -347,7 +331,7 @@ inline void correct(Geometry& geometry)
template <typename Geometry, typename Strategy>
inline void correct(Geometry& geometry, Strategy const& strategy)
{
resolve_variant::correct<Geometry>::apply(geometry, strategy);
resolve_dynamic::correct<Geometry>::apply(geometry, strategy);
}
#if defined(_MSC_VER)

View File

@@ -2,6 +2,11 @@
// Copyright (c) 2017 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2020-2023.
// Modifications copyright (c) 2020-2023 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)
@@ -9,26 +14,18 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
#include <cstddef>
#include <boost/range.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/algorithms/disjoint.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/adapted/boost_variant.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/detail/multi_modify.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
@@ -43,59 +40,55 @@ namespace boost { namespace geometry
namespace detail { namespace correct_closure
{
template <typename Geometry>
struct nop
{
template <typename Geometry>
static inline void apply(Geometry& )
{}
};
// Close a ring, if not closed, or open it
template <typename Ring>
struct close_or_open_ring
{
template <typename Ring>
static inline void apply(Ring& r)
{
if (boost::size(r) <= 2)
auto size = boost::size(r);
if (size <= 2)
{
return;
}
bool const disjoint = geometry::disjoint(*boost::begin(r),
*(boost::end(r) - 1));
closure_selector const s = geometry::closure<Ring>::value;
// TODO: This requires relate(pt, pt) strategy
bool const disjoint = geometry::disjoint(*boost::begin(r), *(boost::end(r) - 1));
closure_selector const closure = geometry::closure<Ring>::value;
if (disjoint && s == closed)
if (disjoint && closure == closed)
{
// Close it by adding first point
geometry::append(r, *boost::begin(r));
}
else if (! disjoint && s != closed)
else if (! disjoint && closure == open)
{
// Open it by removing last point
geometry::traits::resize<Ring>::apply(r, boost::size(r) - 1);
range::resize(r, size - 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;
template <typename Polygon>
static inline void apply(Polygon& poly)
{
close_or_open_ring<ring_type>::apply(exterior_ring(poly));
close_or_open_ring::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)
auto&& rings = interior_rings(poly);
auto const end = boost::end(rings);
for (auto it = boost::begin(rings); it != end; ++it)
{
close_or_open_ring<ring_type>::apply(*it);
close_or_open_ring::apply(*it);
}
}
};
@@ -114,45 +107,45 @@ struct correct_closure: not_implemented<Tag>
template <typename Point>
struct correct_closure<Point, point_tag>
: detail::correct_closure::nop<Point>
: detail::correct_closure::nop
{};
template <typename LineString>
struct correct_closure<LineString, linestring_tag>
: detail::correct_closure::nop<LineString>
: detail::correct_closure::nop
{};
template <typename Segment>
struct correct_closure<Segment, segment_tag>
: detail::correct_closure::nop<Segment>
: detail::correct_closure::nop
{};
template <typename Box>
struct correct_closure<Box, box_tag>
: detail::correct_closure::nop<Box>
: detail::correct_closure::nop
{};
template <typename Ring>
struct correct_closure<Ring, ring_tag>
: detail::correct_closure::close_or_open_ring<Ring>
: detail::correct_closure::close_or_open_ring
{};
template <typename Polygon>
struct correct_closure<Polygon, polygon_tag>
: detail::correct_closure::close_or_open_polygon<Polygon>
: detail::correct_closure::close_or_open_polygon
{};
template <typename MultiPoint>
struct correct_closure<MultiPoint, multi_point_tag>
: detail::correct_closure::nop<MultiPoint>
: detail::correct_closure::nop
{};
template <typename MultiLineString>
struct correct_closure<MultiLineString, multi_linestring_tag>
: detail::correct_closure::nop<MultiLineString>
: detail::correct_closure::nop
{};
@@ -160,11 +153,7 @@ 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
>
>
{};
@@ -176,7 +165,7 @@ struct correct_closure<Geometry, multi_polygon_tag>
namespace resolve_variant
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct correct_closure
{
static inline void apply(Geometry& geometry)
@@ -186,29 +175,37 @@ struct correct_closure
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct_closure<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct correct_closure<Geometry, dynamic_geometry_tag>
{
struct visitor: boost::static_visitor<void>
static void apply(Geometry& geometry)
{
template <typename Geometry>
void operator()(Geometry& geometry) const
traits::visit<Geometry>::apply([](auto & g)
{
correct_closure<Geometry>::apply(geometry);
}
};
correct_closure<util::remove_cref_t<decltype(g)>>::apply(g);
}, geometry);
}
};
static inline void
apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
template <typename Geometry>
struct correct_closure<Geometry, geometry_collection_tag>
{
static void apply(Geometry& geometry)
{
visitor vis;
boost::apply_visitor(vis, geometry);
detail::visit_breadth_first([](auto & g)
{
correct_closure<util::remove_cref_t<decltype(g)>>::apply(g);
return true;
}, geometry);
}
};
} // namespace resolve_variant
// TODO: This algorithm should use relate(pt, pt) strategy
/*!
\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

View File

@@ -4,8 +4,8 @@
// 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.
// This file was modified by Oracle on 2013-2022.
// Modifications copyright (c) 2013-2022 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -22,6 +22,7 @@
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation_gc.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP

View File

@@ -5,8 +5,8 @@
// 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.
// This file was modified by Oracle on 2014-2022.
// Modifications copyright (c) 2014-2022 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -22,15 +22,18 @@
#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/gc_topological_dimension.hpp>
#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
#include <boost/geometry/algorithms/relate.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.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/relate/cartesian.hpp>
#include <boost/geometry/strategies/relate/geographic.hpp>
#include <boost/geometry/strategies/relate/spherical.hpp>
#include <boost/geometry/views/detail/geometry_collection_view.hpp>
namespace boost { namespace geometry
@@ -58,6 +61,82 @@ struct crosses
{};
template <typename Geometry1, typename Geometry2>
struct crosses<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
int const dimension1 = detail::gc_topological_dimension(geometry1);
int const dimension2 = detail::gc_topological_dimension(geometry2);
if (dimension1 >= 0 && dimension2 >= 0)
{
if (dimension1 < dimension2)
{
return detail::relate::relate_impl
<
detail::de9im::static_mask_crosses_d1_le_d2_type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
else if (dimension1 > dimension2)
{
return detail::relate::relate_impl
<
detail::de9im::static_mask_crosses_d2_le_d1_type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
else if (dimension1 == 1 && dimension2 == 1)
{
return detail::relate::relate_impl
<
detail::de9im::static_mask_crosses_d1_1_d2_1_type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
}
return false;
}
};
template <typename Geometry1, typename Geometry2, typename Tag1>
struct crosses<Geometry1, Geometry2, Tag1, geometry_collection_tag>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
using gc1_view_t = detail::geometry_collection_view<Geometry1>;
return crosses
<
gc1_view_t, Geometry2
>::apply(gc1_view_t(geometry1), geometry2, strategy);
}
};
template <typename Geometry1, typename Geometry2, typename Tag2>
struct crosses<Geometry1, Geometry2, geometry_collection_tag, Tag2>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
using gc2_view_t = detail::geometry_collection_view<Geometry2>;
return crosses
<
Geometry1, gc2_view_t
>::apply(geometry1, gc2_view_t(geometry2), strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
@@ -65,9 +144,14 @@ struct crosses
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct crosses
{
template <typename Geometry1, typename Geometry2, typename Strategy>
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
@@ -75,148 +159,146 @@ struct crosses
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return dispatch::crosses<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
return dispatch::crosses
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
};
template <typename Strategy>
struct crosses<Strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
//using strategies::crosses::services::strategy_converter;
using strategies::relate::services::strategy_converter;
return crosses
<
decltype(strategy_converter<Strategy>::get(strategy))
>::apply(geometry1, geometry2,
strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct crosses<default_strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategy::relate::services::default_strategy
//typedef typename strategies::crosses::services::default_strategy
typedef typename strategies::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return apply(geometry1, geometry2, strategy_type());
return crosses
<
strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
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,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct crosses
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::crosses
<
Strategy
>::apply(geometry1, geometry2, 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)
template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
struct crosses<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Strategy>
static inline bool apply(DynamicGeometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
bool result = false;
traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
{
return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
}
};
} // namespace resolve_variant
result = resolve_strategy::crosses
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
struct crosses<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
bool result = false;
traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
{
result = resolve_strategy::crosses
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
template <typename DynamicGeometry1, typename DynamicGeometry2>
struct crosses<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag>
{
template <typename Strategy>
static inline bool apply(DynamicGeometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
bool result = false;
traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
{
result = resolve_strategy::crosses
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_dynamic
/*!
\brief \brief_check2{crosses}
\ingroup crosses
@@ -236,7 +318,7 @@ inline bool crosses(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_variant::crosses
return resolve_dynamic::crosses
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
@@ -252,11 +334,16 @@ inline bool crosses(Geometry1 const& geometry1,
\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
return resolve_dynamic::crosses
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, default_strategy());

View File

@@ -0,0 +1,41 @@
// 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_ALGORITHMS_DEFAULT_AREA_RESULT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_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_ALGORITHMS_DEFAULT_AREA_RESULT_HPP

View File

@@ -1,7 +1,9 @@
// Boost.Geometry
// Copyright (c) 2017-2018, Oracle and/or its affiliates.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2017-2023, 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
// Licensed under the Boost Software License version 1.0.
@@ -11,25 +13,29 @@
#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>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exception.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/densify/cartesian.hpp>
#include <boost/geometry/strategies/densify/geographic.hpp>
#include <boost/geometry/strategies/densify/spherical.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/util/constexpr.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
@@ -68,24 +74,24 @@ inline void convert_and_push_back(Range & range, Point const& p)
template <bool AppendLastPoint = true>
struct densify_range
{
template <typename FwdRng, typename MutRng, typename T, typename Strategy>
template <typename FwdRng, typename MutRng, typename T, typename Strategies>
static inline void apply(FwdRng const& rng, MutRng & rng_out,
T const& len, Strategy const& strategy)
T const& len, Strategies const& strategies)
{
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);
auto it = boost::begin(rng);
auto const end = boost::end(rng);
if (it == end) // empty(rng)
{
return;
}
auto strategy = strategies.densify(rng);
push_back_policy<MutRng> policy(rng_out);
iterator_t prev = it;
auto prev = it;
for ( ++it ; it != end ; prev = it++)
{
point_t const& p0 = *prev;
@@ -96,7 +102,7 @@ struct densify_range
strategy.apply(p0, p1, policy, len);
}
if (BOOST_GEOMETRY_CONDITION(AppendLastPoint))
if BOOST_GEOMETRY_CONSTEXPR (AppendLastPoint)
{
convert_and_push_back(rng_out, *prev); // back(rng)
}
@@ -106,25 +112,25 @@ struct densify_range
template <bool IsClosed1, bool IsClosed2> // false, X
struct densify_ring
{
template <typename Geometry, typename GeometryOut, typename T, typename Strategy>
template <typename Geometry, typename GeometryOut, typename T, typename Strategies>
static inline void apply(Geometry const& ring, GeometryOut & ring_out,
T const& len, Strategy const& strategy)
T const& len, Strategies const& strategies)
{
geometry::detail::densify::densify_range<true>
::apply(ring, ring_out, len, strategy);
::apply(ring, ring_out, len, strategies);
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);
auto const& p0 = range::back(ring);
auto const& p1 = range::front(ring);
auto strategy = strategies.densify(ring);
push_back_policy<GeometryOut> policy(ring_out);
strategy.apply(p0, p1, policy, len);
if (BOOST_GEOMETRY_CONDITION(IsClosed2))
if BOOST_GEOMETRY_CONSTEXPR (IsClosed2)
{
convert_and_push_back(ring_out, p1);
}
@@ -141,6 +147,15 @@ struct densify_ring<true, false>
: densify_range<false>
{};
struct densify_convert
{
template <typename GeometryIn, typename GeometryOut, typename T, typename Strategy>
static void apply(GeometryIn const& in, GeometryOut &out,
T const& , Strategy const& )
{
geometry::convert(in, out);
}
};
}} // namespace detail::densify
#endif // DOXYGEN_NO_DETAIL
@@ -162,6 +177,26 @@ struct densify
: not_implemented<Tag1, Tag2>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, point_tag, point_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, segment_tag, segment_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, box_tag, box_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, multi_point_tag, multi_point_tag>
: geometry::detail::densify::densify_convert
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, linestring_tag, linestring_tag>
: geometry::detail::densify::densify_range<>
@@ -260,43 +295,72 @@ struct densify<Geometry, GeometryOut, multi_polygon_tag, multi_polygon_tag>
namespace resolve_strategy
{
template
<
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct densify
{
template <typename Geometry, typename Distance, typename Strategy>
template <typename Geometry, typename Distance>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategies const& strategies)
{
dispatch::densify
<
Geometry, Geometry
>::apply(geometry, out, max_distance, strategies);
}
};
template <typename Strategy>
struct densify<Strategy, false>
{
template <typename Geometry, typename Distance>
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);
}
using strategies::densify::services::strategy_converter;
dispatch::densify
<
Geometry, Geometry
>::apply(geometry, out, max_distance,
strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct densify<default_strategy, false>
{
template <typename Geometry, typename Distance>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
default_strategy)
default_strategy const&)
{
typedef typename strategy::densify::services::default_strategy
typedef typename strategies::densify::services::default_strategy
<
typename cs_tag<Geometry>::type
>::type strategy_type;
/*BOOST_CONCEPT_ASSERT(
(concepts::DensifyStrategy<strategy_type>)
);*/
Geometry
>::type strategies_type;
apply(geometry, out, max_distance, strategy_type());
dispatch::densify
<
Geometry, Geometry
>::apply(geometry, out, max_distance, strategies_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct densify
{
template <typename Distance, typename Strategy>
@@ -305,47 +369,55 @@ struct densify
Distance const& max_distance,
Strategy const& strategy)
{
resolve_strategy::densify::apply(geometry, out, max_distance, strategy);
resolve_strategy::densify
<
Strategy
>::apply(geometry, out, max_distance, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct densify<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
struct densify<Geometry, dynamic_geometry_tag>
{
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,
apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
boost::apply_visitor(
visitor<Distance, Strategy>(max_distance, strategy),
geometry,
out
);
traits::visit<Geometry>::apply([&](auto const& g)
{
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
densify<geom_t>::apply(g, o, max_distance, strategy);
out = std::move(o);
}, geometry);
}
};
} // namespace resolve_variant
template <typename Geometry>
struct densify<Geometry, geometry_collection_tag>
{
template <typename Distance, typename Strategy>
static inline void
apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
detail::visit_breadth_first([&](auto const& g)
{
using geom_t = util::remove_cref_t<decltype(g)>;
geom_t o;
densify<geom_t>::apply(g, o, max_distance, strategy);
traits::emplace_back<Geometry>::apply(out, std::move(o));
return true;
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
@@ -391,7 +463,7 @@ inline void densify(Geometry const& geometry,
geometry::clear(out);
resolve_variant::densify
resolve_dynamic::densify
<
Geometry
>::apply(geometry, out, max_distance, strategy);

View File

@@ -1,105 +0,0 @@
// 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_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>
#include <boost/geometry/util/add_const_if_c.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename GeometryTag, typename Geometry, typename Range, bool IsConst>
struct as_range
{
static inline typename add_const_if_c<IsConst, Range>::type& get(
typename add_const_if_c<IsConst, Geometry>::type& input)
{
return input;
}
};
template <typename Geometry, typename Range, bool IsConst>
struct as_range<polygon_tag, Geometry, Range, IsConst>
{
static inline typename add_const_if_c<IsConst, Range>::type& get(
typename add_const_if_c<IsConst, Geometry>::type& 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,
false
>::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,
Range,
true
>::get(input);
}
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP

View File

@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2021.
// Modifications copyright (c) 2021, 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.
@@ -17,8 +21,12 @@
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/util/algorithm.hpp>
namespace boost { namespace geometry
@@ -49,10 +57,14 @@ 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);
detail::for_each_dimension<Geometry>([&](auto dimension)
{
geometry::set<Index, dimension>(geometry,
boost::numeric_cast
<
typename coordinate_type<Geometry>::type
>(geometry::get<dimension>(point)));
});
}
@@ -77,10 +89,14 @@ 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);
detail::for_each_dimension<Geometry>([&](auto dimension)
{
geometry::set<dimension>(point,
boost::numeric_cast
<
typename coordinate_type<Point>::type
>(geometry::get<Index, dimension>(geometry)));
});
}

View File

@@ -7,10 +7,11 @@
// 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.
// Modifications copyright (c) 2018, Oracle and/or its affiliates.
// This file was modified by Oracle on 2018-2021.
// Modifications copyright (c) 2018-2021, 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
@@ -21,26 +22,24 @@
#include <cstddef>
#include <type_traits>
#include <boost/concept/requires.hpp>
#include <boost/concept_check.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/if.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/algorithm.hpp>
#include <boost/geometry/util/is_inverse_spheroidal_coordinates.hpp>
#include <boost/geometry/util/for_each_coordinate.hpp>
namespace boost { namespace geometry
@@ -51,33 +50,18 @@ 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);
typedef typename coordinate_type<Point>::type coordinate_type;
coordinate_type const zero = 0;
detail::for_each_dimension<Point>([&](auto dimension)
{
set<dimension>(point, zero);
});
}
};
@@ -88,15 +72,15 @@ 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;
typedef typename coordinate_type<BoxOrSegment>::type coordinate_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()
);
coordinate_type const highest = geometry::bounds<coordinate_type>::highest();
coordinate_type const lowest = geometry::bounds<coordinate_type>::lowest();
detail::for_each_dimension<BoxOrSegment>([&](auto dimension)
{
set<0, dimension>(geometry, highest);
set<1, dimension>(geometry, lowest);
});
}
};
@@ -109,12 +93,12 @@ struct assign_zero_box_or_segment
{
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()
);
coordinate_type const zero = 0;
detail::for_each_dimension<BoxOrSegment>([&](auto dimension)
{
set<0, dimension>(geometry, zero);
set<1, dimension>(geometry, zero);
});
}
};
@@ -139,90 +123,6 @@ inline void assign_box_2d_corner(Box const& box, Point& point)
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
{
@@ -254,11 +154,9 @@ namespace dispatch
template <typename GeometryTag, typename Geometry, std::size_t DimensionCount>
struct assign
{
BOOST_MPL_ASSERT_MSG
(
false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
, (types<Geometry>)
);
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>

View File

@@ -1,152 +0,0 @@
// 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

View File

View File

@@ -1,9 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2022-2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
// This file was modified by Oracle on 2017-2022.
// Modifications copyright (c) 2017-2022 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,
@@ -16,30 +17,38 @@
#include <cstddef>
#include <iterator>
#include <boost/core/ignore_unused.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range.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/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/strategies/side.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/detail/buffer/parallel_continue.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
#include <boost/geometry/util/constexpr.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/type_traits.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
@@ -49,10 +58,11 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
template <typename Range, typename DistanceStrategy>
inline void simplify_input(Range const& range,
DistanceStrategy const& distance,
Range& simplified)
template <typename RangeIn, typename DistanceStrategy, typename RangeOut, typename Strategies>
inline void simplify_input(RangeIn const& range,
DistanceStrategy const& distance,
RangeOut& simplified,
Strategies const& strategies)
{
// We have to simplify the ring before to avoid very small-scaled
// features in the original (convex/concave/convex) being enlarged
@@ -64,19 +74,10 @@ inline void simplify_input(Range const& range,
// 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());
detail::simplify::douglas_peucker(),
strategies);
}
@@ -92,10 +93,11 @@ struct buffer_range
typename Collection,
typename Point,
typename DistanceStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline
void add_join(Collection& collection,
@@ -108,26 +110,15 @@ struct buffer_range
output_point_type const& perp2,
geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& ,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
output_point_type intersection_point;
geometry::assign_zero(intersection_point);
geometry::strategy::buffer::join_selector join
= get_join_type(penultimate_input, previous_input, input, strategy);
if (join == geometry::strategy::buffer::join_convex)
{
// Calculate the intersection-point formed by the two sides.
// It might be that the two sides are not convex, but continue
// or spikey, we then change the join-type
join = line_line_intersection::apply(
perp1, perp2, prev_perp1, prev_perp2,
intersection_point);
}
geometry::strategy::buffer::join_selector const join
= get_join_type(penultimate_input, previous_input, input,
strategies);
switch(join)
{
@@ -161,37 +152,48 @@ struct buffer_range
{
// The corner is convex, we create a join
// TODO (future) - avoid a separate vector, add the piece directly
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))
output_point_type intersection_point;
if (line_line_intersection::apply(prev_perp1, prev_perp2,
perp1, perp2, previous_input,
segment_strategy.equidistant(),
intersection_point))
{
collection.add_piece(geometry::strategy::buffer::buffered_join,
previous_input, range_out);
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;
}
}
template <typename Strategy>
// 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 Strategies>
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,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
int const side = strategy.apply(p0, p1, p2);
int const side = strategies.side().apply(p0, p1, p2);
return side == -1 ? geometry::strategy::buffer::join_convex
: side == 1 ? geometry::strategy::buffer::join_concave
: parallel_continue
(
get<0>(p2) - get<0>(p1),
get<1>(p2) - get<1>(p1),
get<0>(p1) - get<0>(p0),
get<1>(p1) - get<1>(p0)
) ? geometry::strategy::buffer::join_continue
: same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue
: geometry::strategy::buffer::join_spike;
}
@@ -200,28 +202,28 @@ struct buffer_range
typename Collection,
typename Iterator,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
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,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
Strategies const& strategies,
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);
boost::ignore_unused(segment_strategy);
typedef typename std::iterator_traits
<
@@ -263,7 +265,7 @@ struct buffer_range
{
generated_side.clear();
geometry::strategy::buffer::result_code error_code
= side_strategy.apply(*prev, *it, side,
= segment_strategy.apply(*prev, *it, side,
distance_strategy, generated_side);
if (error_code == geometry::strategy::buffer::result_no_output)
@@ -289,15 +291,15 @@ struct buffer_range
*prev, last_p1, last_p2,
*it, generated_side.front(), generated_side.back(),
side,
distance_strategy, join_strategy, end_strategy,
robust_policy, strategy);
distance_strategy, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies);
}
collection.add_side_piece(*prev, *it, generated_side, first);
collection.add_side_piece(*prev, *it, generated_side, first, distance_strategy.empty(side));
if (first && mark_flat)
{
collection.mark_flat_start();
collection.mark_flat_start(*prev);
}
penultimate_point = *prev;
@@ -316,7 +318,7 @@ struct buffer_range
if (mark_flat)
{
collection.mark_flat_end();
collection.mark_flat_end(ultimate_point);
}
return result;
@@ -335,32 +337,29 @@ struct buffer_multi
<
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline void apply(Multi const& multi,
Collection& collection,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
for (typename boost::range_iterator<Multi const>::type
it = boost::begin(multi);
it != boost::end(multi);
++it)
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
Policy::apply(*it, collection,
distance_strategy, side_strategy,
distance_strategy, segment_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, strategy);
robust_policy, strategies);
}
}
};
@@ -423,21 +422,21 @@ struct buffer_inserter<point_tag, Point, RingOutput>
<
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline void apply(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
SideStrategy const& ,
SegmentStrategy const& ,
JoinStrategy const& ,
EndStrategy const& ,
PointStrategy const& point_strategy,
RobustPolicy const& ,
Strategy const& ) // side strategy
Strategies const& )
{
detail::buffer::buffer_point
<
@@ -455,28 +454,28 @@ template
>
struct buffer_inserter_ring
{
typedef typename point_type<RingOutput>::type output_point_type;
using output_point_type = typename point_type<RingOutput>::type;
template
<
typename Collection,
typename Iterator,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
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,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
output_point_type first_p1, first_p2, last_p1, last_p2;
@@ -485,8 +484,8 @@ struct buffer_inserter_ring
geometry::strategy::buffer::result_code result
= buffer_range::iterate(collection, begin, end,
side,
distance_strategy, side_strategy, join_strategy, end_strategy,
robust_policy, strategy,
distance_strategy, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies,
false, first_p1, first_p2, last_p1, last_p2);
// Generate closing join
@@ -497,8 +496,8 @@ struct buffer_inserter_ring
*(end - 1), last_p1, last_p2,
*(begin + 1), first_p1, first_p2,
side,
distance_strategy, join_strategy, end_strategy,
robust_policy, strategy);
distance_strategy, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies);
}
// Buffer is closed automatically by last closing corner
@@ -509,51 +508,58 @@ struct buffer_inserter_ring
<
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
RingInput simplified;
detail::buffer::simplify_input(ring, distance, simplified);
// Use helper geometry to support non-mutable input Rings
using simplified_ring_t = model::ring
<
output_point_type,
point_order<RingInput>::value != counterclockwise,
closure<RingInput>::value != open
>;
simplified_ring_t simplified;
detail::buffer::simplify_input(ring, distance, simplified, strategies);
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
geometry::closure<simplified_ring_t>::value
>::value;
if (n >= min_points)
{
detail::normalized_view<RingInput const> view(simplified);
detail::closed_clockwise_view<simplified_ring_t 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);
distance, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies);
}
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);
distance, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies);
}
}
@@ -582,30 +588,30 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
<
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
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);
segment_strategy, join_strategy, end_strategy, point_strategy,
robust_policy, strategies);
collection.finish_ring(code, ring, false, false);
return code;
}
};
@@ -617,34 +623,33 @@ template
>
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;
using output_ring_type = typename ring_type<Polygon>::type;
using output_point_type = typename point_type<output_ring_type>::type;
template
<
typename Collection,
typename Iterator,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
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,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
Strategies const& strategies,
output_point_type& first_p1)
{
input_point_type const& ultimate_point = *(end - 1);
input_point_type const& penultimate_point = *(end - 2);
output_point_type const& ultimate_point = *(end - 1);
output_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),
@@ -659,7 +664,7 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
{
std::vector<output_point_type> generated_side;
geometry::strategy::buffer::result_code code
= side_strategy.apply(ultimate_point, penultimate_point,
= segment_strategy.apply(ultimate_point, penultimate_point,
geometry::strategy::buffer::buffer_side_right,
distance_strategy, generated_side);
if (code != geometry::strategy::buffer::result_normal)
@@ -675,8 +680,8 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
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,
distance_strategy, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies,
true, first_p1, first_p2, last_p1, last_p2);
if (result == geometry::strategy::buffer::result_normal)
@@ -693,25 +698,26 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
<
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
Linestring simplified;
detail::buffer::simplify_input(linestring, distance, simplified);
// Use helper geometry to support non-mutable input Linestrings
model::linestring<output_point_type> simplified;
detail::buffer::simplify_input(linestring, distance, simplified, strategies);
geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
@@ -722,8 +728,8 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
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,
distance, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies,
first_p1);
if (code == geometry::strategy::buffer::result_normal)
@@ -731,8 +737,8 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
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,
distance, segment_strategy, join_strategy, end_strategy,
robust_policy, strategies,
first_p1);
}
collection.finish_ring(code);
@@ -770,23 +776,23 @@ private:
typename Iterator,
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline
void iterate(Iterator begin, Iterator end,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy, // side strategy
Strategies const& strategies,
bool is_interior)
{
for (Iterator it = begin; it != end; ++it)
@@ -799,11 +805,11 @@ private:
collection.start_new_ring(deflate);
geometry::strategy::buffer::result_code const code
= policy::apply(*it, collection, distance, side_strategy,
= policy::apply(*it, collection, distance, segment_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, strategy);
robust_policy, strategies);
collection.finish_ring(code, is_interior);
collection.finish_ring(code, *it, is_interior, false);
}
}
@@ -812,28 +818,28 @@ private:
typename InteriorRings,
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline
void apply_interior_rings(InteriorRings const& interior_rings,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
iterate(boost::begin(interior_rings), boost::end(interior_rings),
collection, distance, side_strategy,
collection, distance, segment_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, strategy, true);
robust_policy, strategies, true);
}
public:
@@ -841,40 +847,40 @@ public:
<
typename Collection,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename RobustPolicy,
typename Strategy
typename Strategies
>
static inline void apply(PolygonInput const& polygon,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
Strategy const& strategy) // side strategy
Strategies const& strategies)
{
{
collection.start_new_ring(distance.negative());
geometry::strategy::buffer::result_code const code
= policy::apply(exterior_ring(polygon), collection,
distance, side_strategy,
distance, segment_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, strategy);
robust_policy, strategies);
collection.finish_ring(code, false,
collection.finish_ring(code, exterior_ring(polygon), false,
geometry::num_interior_rings(polygon) > 0u);
}
apply_interior_rings(interior_rings(polygon),
collection, distance, side_strategy,
collection, distance, segment_strategy,
join_strategy, end_strategy, point_strategy,
robust_policy, strategy);
robust_policy, strategies);
}
};
@@ -915,41 +921,38 @@ template
typename GeometryInput,
typename OutputIterator,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename IntersectionStrategy,
typename Strategies,
typename RobustPolicy,
typename VisitPiecesPolicy
>
inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
IntersectionStrategy const& intersection_strategy,
Strategies const& strategies,
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,
RobustPolicy
> collection_type;
collection_type collection(intersection_strategy, robust_policy);
using collection_type = detail::buffer::buffered_piece_collection
<
typename geometry::ring_type<GeometryOutput>::type,
Strategies,
DistanceStrategy,
RobustPolicy
>;
collection_type collection(strategies, distance_strategy, robust_policy);
collection_type const& const_collection = collection;
bool const areal = boost::is_same
<
typename tag_cast<typename tag<GeometryInput>::type, areal_tag>::type,
areal_tag
>::type::value;
static constexpr bool areal = util::is_areal<GeometryInput>::value;
dispatch::buffer_inserter
<
@@ -961,17 +964,18 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
GeometryInput,
GeometryOutput
>::apply(geometry_input, collection,
distance_strategy, side_strategy, join_strategy,
end_strategy, point_strategy,
robust_policy, intersection_strategy.get_side_strategy());
distance_strategy, segment_strategy, join_strategy,
end_strategy, point_strategy,
robust_policy, strategies);
collection.get_turns();
collection.classify_turns();
if (BOOST_GEOMETRY_CONDITION(areal))
if BOOST_GEOMETRY_CONSTEXPR (areal)
{
collection.check_remaining_points(distance_strategy);
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
@@ -985,6 +989,11 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
// phase 1: turns (after enrichment/clustering)
visit_pieces_policy.apply(const_collection, 1);
if BOOST_GEOMETRY_CONSTEXPR (areal)
{
collection.deflate_check_turns();
}
collection.traverse();
// Reverse all offsetted rings / traversed rings if:
@@ -992,8 +1001,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
// - 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))
if BOOST_GEOMETRY_CONSTEXPR (geometry::point_order<GeometryOutput>::value == counterclockwise)
{
reverse = ! reverse;
}
@@ -1002,9 +1010,12 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
collection.reverse();
}
if (BOOST_GEOMETRY_CONDITION(distance_strategy.negative() && areal))
if BOOST_GEOMETRY_CONSTEXPR (areal)
{
collection.discard_nonintersecting_deflated_rings();
if (distance_strategy.negative())
{
collection.discard_nonintersecting_deflated_rings();
}
}
collection.template assign<GeometryOutput>(out);
@@ -1020,27 +1031,27 @@ template
typename GeometryInput,
typename OutputIterator,
typename DistanceStrategy,
typename SideStrategy,
typename SegmentStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename IntersectionStrategy,
typename Strategies,
typename RobustPolicy
>
inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
SegmentStrategy const& segment_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
IntersectionStrategy const& intersection_strategy,
Strategies const& strategies,
RobustPolicy const& robust_policy)
{
detail::buffer::visit_pieces_default_policy visitor;
buffer_inserter<GeometryOutput>(geometry_input, out,
distance_strategy, side_strategy, join_strategy,
distance_strategy, segment_strategy, join_strategy,
end_strategy, point_strategy,
intersection_strategy, robust_policy, visitor);
strategies, robust_policy, visitor);
}
#endif // DOXYGEN_NO_DETAIL

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
// 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,
@@ -15,12 +15,11 @@
#include <cstddef>
#include <boost/range.hpp>
#include <boost/range/value_type.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/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
@@ -36,12 +35,6 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
enum intersection_location_type
{
location_ok, inside_buffer, location_discard
};
class backtrack_for_buffer
{
public :
@@ -146,8 +139,8 @@ struct buffer_turn_operation
{}
};
// Version for buffer including type of location, is_opposite, and helper variables
template <typename Point, typename RobustPoint, typename SegmentRatio>
// 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
<
@@ -157,73 +150,144 @@ struct buffer_turn_info
>
{
typedef Point point_type;
typedef RobustPoint robust_point_type;
std::size_t turn_index; // TODO: this might go if partition can operate on non-const input
std::size_t turn_index;
RobustPoint robust_point;
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
// Will (most probably) be removed later
RobustPoint mapped_robust_point; // alas... we still need to adapt our points, offsetting them 1 integer to be co-located with neighbours
#endif
inline RobustPoint const& get_robust_point() const
{
#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
return mapped_robust_point;
#endif
return robust_point;
}
intersection_location_type location;
robust_point_type rob_pi, rob_pj, rob_qi, rob_qj;
std::size_t count_within;
// 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 is_linear_end_point;
bool within_original;
std::size_t count_on_original_boundary;
signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring
std::size_t count_on_offsetted;
std::size_t count_on_helper;
std::size_t count_within_near_offsetted;
bool remove_on_multi;
// Obsolete:
std::size_t count_on_occupied;
std::size_t count_on_multi;
inline buffer_turn_info()
: turn_index(0)
, location(location_ok)
, count_within(0)
, is_turn_traversable(true)
, is_linear_end_point(false)
, within_original(false)
, count_on_original_boundary(0)
, count_in_original(0)
, count_on_offsetted(0)
, count_on_helper(0)
, count_within_near_offsetted(0)
, remove_on_multi(false)
, count_on_occupied(0)
, count_on_multi(0)
{}
};
struct buffer_operation_less
struct buffer_less
{
template <typename Turn>
inline bool operator()(Turn const& left, Turn const& right) const
template <typename Indexed>
inline bool operator()(Indexed const& left, Indexed const& right) const
{
segment_identifier const& sl = left.seg_id;
segment_identifier const& sr = right.seg_id;
if (! (left.subject->seg_id == right.subject->seg_id))
{
return left.subject->seg_id < right.subject->seg_id;
}
// Sort them descending
return sl == sr
? left.fraction < right.fraction
: sl < sr;
// 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;
}
};
template <typename Strategy>
struct piece_get_box
{
explicit piece_get_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Piece>
inline void apply(Box& total, Piece const& piece) const
{
assert_coordinate_type_equal(total, piece.m_piece_border.m_envelope);
if (piece.m_piece_border.m_has_envelope)
{
geometry::expand(total, piece.m_piece_border.m_envelope,
m_strategy);
}
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct piece_overlaps_box
{
explicit piece_overlaps_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Piece>
inline bool apply(Box const& box, Piece const& piece) const
{
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,
m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct turn_get_box
{
explicit turn_get_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Turn>
inline void apply(Box& total, Turn const& turn) const
{
assert_coordinate_type_equal(total, turn.point);
geometry::expand(total, turn.point, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct turn_overlaps_box
{
explicit turn_overlaps_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Turn>
inline bool apply(Box const& box, Turn const& turn) const
{
assert_coordinate_type_equal(turn.point, box);
return ! geometry::detail::disjoint::disjoint_point_box(turn.point, box,
m_strategy);
}
Strategy const& m_strategy;
};
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;
}
};

View File

@@ -2,6 +2,10 @@
// 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)
@@ -12,7 +16,8 @@
#include <cstddef>
#include <boost/range.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>
@@ -78,11 +83,14 @@ struct buffered_ring_collection : public std::vector<Ring>
// Turn off concept checking (for now)
namespace dispatch
namespace concepts
{
template <typename Geometry, bool IsConst>
struct check<Geometry, detail::buffer::buffered_ring_collection_tag, IsConst>
template <typename Geometry>
struct concept_type<Geometry, geometry::detail::buffer::buffered_ring_collection_tag>
{
struct dummy {};
using type = dummy;
};
}

View File

@@ -3,8 +3,8 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017, 2018.
// Modifications copyright (c) 2017-2018 Oracle and/or its affiliates.
// 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,
@@ -15,11 +15,12 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range.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/expand.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>
@@ -116,7 +117,7 @@ template
typename Pieces,
typename Rings,
typename Turns,
typename IntersectionStrategy,
typename Strategy,
typename RobustPolicy
>
class piece_turn_visitor
@@ -124,7 +125,7 @@ class piece_turn_visitor
Pieces const& m_pieces;
Rings const& m_rings;
Turns& m_turns;
IntersectionStrategy const& m_intersection_strategy;
Strategy const& m_strategy;
RobustPolicy const& m_robust_policy;
template <typename Piece>
@@ -150,7 +151,6 @@ class piece_turn_visitor
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,
@@ -194,7 +194,6 @@ class piece_turn_visitor
{
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;
@@ -213,12 +212,12 @@ class piece_turn_visitor
// 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;
auto it1_first = boost::begin(ring1) + sec1_first_index;
auto 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;
auto it2_first = boost::begin(ring2) + sec2_first_index;
auto 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;
@@ -246,41 +245,32 @@ class piece_turn_visitor
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++;
auto it1 = it1_first;
for (auto 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
geometry::recalculate(the_model.rob_pi, *prev1, m_robust_policy);
geometry::recalculate(the_model.rob_pj, *it1, m_robust_policy);
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
iterator it2 = it2_first;
for (iterator prev2 = it2++;
auto it2 = it2_first;
for (auto 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);
geometry::recalculate(the_model.rob_qi, *prev2, m_robust_policy);
geometry::recalculate(the_model.rob_qj, *it2, m_robust_policy);
// TODO: internally get_turn_info calculates robust points.
// But they are already calculated.
// We should be able to use them.
// this means passing them to this visitor,
// and iterating in sync with them...
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_null_policy
detail::overlay::assign_policy_only_start_turns
> turn_policy;
turn_policy::apply(unique_sub_range1, unique_sub_range2,
the_model,
m_intersection_strategy,
m_strategy,
m_robust_policy,
std::back_inserter(m_turns));
}
@@ -292,12 +282,12 @@ public:
piece_turn_visitor(Pieces const& pieces,
Rings const& ring_collection,
Turns& turns,
IntersectionStrategy const& intersection_strategy,
Strategy const& strategy,
RobustPolicy const& robust_policy)
: m_pieces(pieces)
, m_rings(ring_collection)
, m_turns(turns)
, m_intersection_strategy(intersection_strategy)
, m_strategy(strategy)
, m_robust_policy(robust_policy)
{}
@@ -316,7 +306,7 @@ public:
|| 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()) )
m_strategy) )
{
return true;
}

View File

@@ -0,0 +1,214 @@
// 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-2022.
// Modifications copyright (c) 2017-2022 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_BUFFER_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_IMPLEMENTATION_HPP
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_box.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp>
#include <boost/geometry/algorithms/detail/buffer/interface.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp> // for GC
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/union.hpp> // for GC
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/strategies/buffer/cartesian.hpp>
#include <boost/geometry/strategies/buffer/geographic.hpp>
#include <boost/geometry/strategies/buffer/spherical.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename BoxIn, typename BoxOut>
struct buffer_dc<BoxIn, BoxOut, box_tag, box_tag>
{
template <typename Distance>
static inline void apply(BoxIn const& box_in, BoxOut& box_out,
Distance const& distance, Distance const& )
{
detail::buffer::buffer_box(box_in, distance, box_out);
}
};
template <typename Input, typename Output, typename TagIn>
struct buffer_all<Input, Output, TagIn, multi_polygon_tag>
{
template
<
typename DistanceStrategy,
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename Strategies
>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
Strategies const& strategies)
{
typedef typename boost::range_value<Output>::type polygon_type;
typedef typename point_type<Input>::type point_type;
typedef typename rescale_policy_type
<
point_type,
typename geometry::cs_tag<point_type>::type
>::type rescale_policy_type;
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));
rescale_policy_type rescale_policy
= boost::geometry::get_rescale_policy<rescale_policy_type>(
box, strategies);
detail::buffer::buffer_inserter<polygon_type>(geometry_in,
range::back_inserter(geometry_out),
distance_strategy,
side_strategy,
join_strategy,
end_strategy,
point_strategy,
strategies,
rescale_policy);
}
};
template <typename Input, typename Output>
struct buffer_all<Input, Output, geometry_collection_tag, multi_polygon_tag>
{
template
<
typename DistanceStrategy,
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename Strategies
>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
Strategies const& strategies)
{
// NOTE: The buffer normally calculates everything at once (by pieces) and traverses all
// of them to apply the union operation. Not even by merging elements. But that is
// complex and has led to issues as well. Here intermediate results are calculated
// with buffer and the results are merged afterwards.
// NOTE: This algorithm merges partial results iteratively.
// We could first gather all of the results and after that
// use some more optimal method like merge_elements().
detail::visit_breadth_first([&](auto const& g)
{
Output buffer_result;
buffer_all
<
util::remove_cref_t<decltype(g)>, Output
>::apply(g, buffer_result, distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy, strategies);
if (! geometry::is_empty(buffer_result))
{
Output union_result;
geometry::union_(geometry_out, buffer_result, union_result, strategies);
geometry_out = std::move(union_result);
}
return true;
}, geometry_in);
}
};
template <typename Input, typename Output>
struct buffer_all<Input, Output, geometry_collection_tag, geometry_collection_tag>
{
template
<
typename DistanceStrategy,
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
typename Strategies
>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
Strategies const& strategies)
{
// NOTE: We could also allow returning GC containing only polygons.
// We'd have to wrap them in model::multi_polygon and then
// iteratively emplace_back() into the GC.
using mpo_t = typename util::sequence_find_if
<
typename traits::geometry_types<Output>::type,
util::is_multi_polygon
>::type;
mpo_t result;
buffer_all
<
Input, mpo_t
>::apply(geometry_in, result, distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy, strategies);
range::emplace_back(geometry_out, std::move(result));
}
};
template <typename Input, typename Output, typename TagIn>
struct buffer_all<Input, Output, TagIn, geometry_collection_tag>
: buffer_all<Input, Output, geometry_collection_tag, geometry_collection_tag>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,279 @@
// 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-2022.
// Modifications copyright (c) 2017-2022 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_BUFFER_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERFACE_HPP
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/buffer/services.hpp>
#include <boost/geometry/util/type_traits_std.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_dc : not_implemented<TagIn, TagOut>
{};
template
<
typename Input,
typename Output,
typename TagIn = typename tag<Input>::type,
typename TagOut = typename tag<Output>::type
>
struct buffer_all : not_implemented<TagIn, TagOut>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_dynamic
{
template
<
typename Input,
typename TagIn = typename geometry::tag<Input>::type
>
struct buffer_dc
{
template <typename Output, typename Distance>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
Distance const& distance,
Distance const& chord_length)
{
dispatch::buffer_dc<Input, Output>::apply(geometry_in, geometry_out, distance, chord_length);
}
};
template <typename Input>
struct buffer_dc<Input, dynamic_geometry_tag>
{
template <typename Output, typename Distance>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
Distance const& distance,
Distance const& chord_length)
{
traits::visit<Input>::apply([&](auto const& g)
{
dispatch::buffer_dc
<
util::remove_cref_t<decltype(g)>, Output
>::apply(g, geometry_out, distance, chord_length);
}, geometry_in);
}
};
template
<
typename Input,
typename TagIn = typename geometry::tag<Input>::type
>
struct buffer_all
{
template
<
typename Output,
typename DistanceStrategy,
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy
>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy)
{
typename strategies::buffer::services::default_strategy
<
Input
>::type strategies;
dispatch::buffer_all
<
Input, Output
>::apply(geometry_in, geometry_out, distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy, strategies);
}
};
template <typename Input>
struct buffer_all<Input, dynamic_geometry_tag>
{
template
<
typename Output,
typename DistanceStrategy,
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy
>
static inline void apply(Input const& geometry_in,
Output& geometry_out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy)
{
traits::visit<Input>::apply([&](auto const& g)
{
buffer_all
<
util::remove_cref_t<decltype(g)>
>::apply(g, geometry_out, distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy);
}, geometry_in);
}
};
} // namespace resolve_dynamic
/*!
\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_dynamic::buffer_dc<Input>::apply(geometry_in, geometry_out, distance, chord_length);
}
/*!
\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>
inline 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_dynamic::buffer_dc<Input>::apply(geometry, geometry_out, distance, chord_length);
return geometry_out;
}
/*!
\brief \brief_calc{buffer}
\ingroup buffer
\details \details_calc{buffer, \det_buffer}.
\tparam GeometryIn \tparam_geometry
\tparam GeometryOut \tparam_geometry{GeometryOut}
\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 geometry, e.g. multi polygon,
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 GeometryOut,
typename DistanceStrategy,
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy
>
inline void buffer(GeometryIn const& geometry_in,
GeometryOut& geometry_out,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy)
{
concepts::check<GeometryIn const>();
concepts::check<GeometryOut>();
geometry::clear(geometry_out);
resolve_dynamic::buffer_all
<
GeometryIn, GeometryOut
>::apply(geometry_in, geometry_out, distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_INTERFACE_HPP

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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
@@ -9,11 +9,9 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
#include <boost/geometry/arithmetic/determinant.hpp>
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/detail/buffer/parallel_continue.hpp>
namespace boost { namespace geometry
{
@@ -23,57 +21,91 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
// TODO: once change this to proper strategy
// It is different from current segment intersection because these are not segments but lines
// If we have the Line concept, we can create a strategy
// Assumes a convex corner
struct line_line_intersection
{
template <typename Point>
static Point between_point(Point const& a, Point const& b)
{
Point result;
geometry::set<0>(result, (geometry::get<0>(a) + geometry::get<0>(b)) / 2.0);
geometry::set<1>(result, (geometry::get<1>(a) + geometry::get<1>(b)) / 2.0);
return result;
}
template <typename Point>
static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj,
Point const& qi, Point const& qj, Point& ip)
static bool
apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj,
Point const& vertex, bool equidistant, Point& ip)
{
// See http://mathworld.wolfram.com/Line-LineIntersection.html
typedef typename coordinate_type<Point>::type coordinate_type;
// Calculates ip (below) by either intersecting p (pi, pj)
// with q (qi, qj) or by taking a point between pj and qi (b) and
// intersecting r (b, v), where v is the original vertex, with p (or q).
// The reason for dual approach: p might be nearly collinear with q,
// and in that case the intersection points can lose precision
// (or be plainly wrong).
// Therefore it takes the most precise option (this is usually p, r)
//
// /qj |
// / |
// / / |
// / / |
// / / |
// /qi / |
// / |
// ip * + b * v |
// \ |
// \pj \ |
// \ \ |
// \ \ |
// \ \ |
// \pi \ |
//
// If generated sides along the segments can have an adapted distance,
// in a custom strategy, then the calculation of the point in between
// might be incorrect and the optimization is not used.
coordinate_type const denominator
= determinant<coordinate_type>(get<0>(pi) - get<0>(pj),
get<1>(pi) - get<1>(pj),
get<0>(qi) - get<0>(qj),
get<1>(qi) - get<1>(qj));
using ct = typename coordinate_type<Point>::type;
// Even if the corner was checked before (so it is convex now), that
// was done on the original geometry. This function runs on the buffered
// geometries, where sides are generated and might be slightly off. In
// Floating Point, that slightly might just exceed the limit and we have
// to check it again.
auto const p = detail::make::make_infinite_line<ct>(pi, pj);
auto const q = detail::make::make_infinite_line<ct>(qi, qj);
// For round joins, it will not be used at all.
// For miter joints, there is a miter limit
// If segments are parallel/collinear we must be distinguish two cases:
// they continue each other, or they form a spike
if (math::equals(denominator, coordinate_type()))
using line = decltype(p);
using arithmetic::determinant;
using arithmetic::assign_intersection_point;
// The denominator is the determinant of (a,b) values of lines p q
// | pa pa |
// | qb qb |
auto const denominator_pq = determinant<line, &line::a, &line::b>(p, q);
constexpr decltype(denominator_pq) const zero = 0;
if (equidistant)
{
return parallel_continue(get<0>(qj) - get<0>(qi),
get<1>(qj) - get<1>(qi),
get<0>(pj) - get<0>(pi),
get<1>(pj) - get<1>(pi))
? strategy::buffer::join_continue
: strategy::buffer::join_spike
;
auto const between = between_point(pj, qi);
auto const r = detail::make::make_infinite_line<ct>(vertex, between);
auto const denominator_pr = determinant<line, &line::a, &line::b>(p, r);
if (math::equals(denominator_pq, zero)
&& math::equals(denominator_pr, zero))
{
// Degenerate case (for example when length results in <inf>)
return false;
}
ip = geometry::math::abs(denominator_pq) > geometry::math::abs(denominator_pr)
? assign_intersection_point<Point>(p, q, denominator_pq)
: assign_intersection_point<Point>(p, r, denominator_pr);
}
else
{
if (math::equals(denominator_pq, zero))
{
return false;
}
ip = assign_intersection_point<Point>(p, q, denominator_pq);
}
coordinate_type d1 = determinant<coordinate_type>(get<0>(pi), get<1>(pi), get<0>(pj), get<1>(pj));
coordinate_type d2 = determinant<coordinate_type>(get<0>(qi), get<1>(qi), get<0>(qj), get<1>(qj));
double const multiplier = 1.0 / denominator;
set<0>(ip, determinant<coordinate_type>(d1, get<0>(pi) - get<0>(pj), d2, get<0>(qi) - get<0>(qj)) * multiplier);
set<1>(ip, determinant<coordinate_type>(d1, get<1>(pi) - get<1>(pj), d2, get<1>(qi) - get<1>(qj)) * multiplier);
return strategy::buffer::join_convex;
return true;
}
};

View File

@@ -1,33 +0,0 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 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_PARALLEL_CONTINUE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename T>
inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2)
{
T const dot = dx1 * dx2 + dy1 * dy2;
return dot > 0;
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP

View File

@@ -0,0 +1,511 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2020-2021 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2020-2022.
// Modifications copyright (c) 2020-2022, 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 <array>
#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_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.
std::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;
}
template <typename Strategy>
void get_properties_of_border(bool is_point_buffer, Point const& center,
Strategy const& strategy)
{
m_has_envelope = calculate_envelope(m_envelope, strategy);
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 Strategy>
void get_properties_of_offsetted_ring_part(Strategy 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, typename Strategy>
bool calculate_envelope(Box& envelope, Strategy const& strategy) 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, strategy);
expand_envelope(envelope, m_originals.begin(), m_originals.begin() + m_original_size, strategy);
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 TiRStrategy,
typename State
>
bool walk_offsetted(TurnPoint const& point, Iterator begin, Iterator end,
TiRStrategy 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 TiRStrategy, typename State>
bool step(TurnPoint const& point, Point const& p1, Point const& p2,
TiRStrategy const& strategy,
geometry::strategy::buffer::place_on_ring_type place_on_ring, State& state) const
{
return strategy.apply(point, p1, p2, place_on_ring, m_is_convex, state);
}
template <typename It, typename Box, typename Strategy>
void expand_envelope(Box& envelope, It begin, It end, Strategy const& strategy) const
{
for (It it = begin; it != end; ++it)
{
geometry::expand(envelope, *it, strategy);
}
}
template <typename Strategy>
bool is_convex(Strategy 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 Strategy>
bool is_convex(Point& previous, Point& current, It begin, It end, Strategy const& strategy) const
{
for (It it = begin; it != end; ++it)
{
if (! is_convex(previous, current, *it, strategy))
{
return false;
}
}
return true;
}
template <typename Strategy>
bool is_convex(Point& previous, Point& current, Point const& next, Strategy const& strategy) const
{
int const side = strategy.side().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, 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

View File

@@ -2,8 +2,9 @@
// 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.
// This file was modified by Oracle on 2016-2023.
// Modifications copyright (c) 2016-2023 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,
@@ -15,8 +16,10 @@
#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/detail/disjoint/interface.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/strategies/buffer.hpp>
@@ -30,24 +33,40 @@ namespace boost { namespace geometry
namespace detail { namespace buffer
{
template <typename Strategy>
struct original_get_box
{
explicit original_get_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Original>
static inline void apply(Box& total, Original const& original)
inline void apply(Box& total, Original const& original) const
{
geometry::expand(total, original.m_box);
assert_coordinate_type_equal(total, original.m_box);
geometry::expand(total, original.m_box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename DisjointBoxBoxStrategy>
struct original_ovelaps_box
template <typename Strategy>
struct original_overlaps_box
{
explicit original_overlaps_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Original>
static inline bool apply(Box const& box, Original const& original)
inline bool apply(Box const& box, Original const& original) const
{
assert_coordinate_type_equal(box, original.m_box);
return ! detail::disjoint::disjoint_box_box(box, original.m_box,
DisjointBoxBoxStrategy());
m_strategy);
}
Strategy const& m_strategy;
};
struct include_turn_policy
@@ -55,25 +74,31 @@ struct include_turn_policy
template <typename Turn>
static inline bool apply(Turn const& turn)
{
return turn.location == location_ok;
return turn.is_turn_traversable;
}
};
template <typename DisjointPointBoxStrategy>
struct turn_in_original_ovelaps_box
template <typename Strategy>
struct turn_in_original_overlaps_box
{
explicit turn_in_original_overlaps_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)
inline bool apply(Box const& box, Turn const& turn) const
{
if (turn.location != location_ok || turn.within_original)
if (! turn.is_turn_traversable || turn.within_original)
{
// Skip all points already processed
return false;
}
return ! geometry::detail::disjoint::disjoint_point_box(
turn.robust_point, box, DisjointPointBoxStrategy());
turn.point, box, m_strategy);
}
Strategy const& m_strategy;
};
//! Check if specified is in range of specified iterators
@@ -150,16 +175,11 @@ inline bool point_in_section(Strategy& strategy, State& state,
}
template <typename Point, typename Original>
inline int point_in_original(Point const& point, Original const& original)
template <typename Point, typename Original, typename PointInGeometryStrategy>
inline int point_in_original(Point const& point, Original const& original,
PointInGeometryStrategy const& strategy)
{
// The winding strategy is scanning in x direction
// therefore it's critical to pass direction calculated
// for x dimension below.
typedef strategy::within::winding<Point> strategy_type;
typename strategy_type::state_type state;
strategy_type strategy;
typename PointInGeometryStrategy::state_type state;
if (boost::size(original.m_sections) == 0
|| boost::size(original.m_ring) - boost::size(original.m_sections) < 16)
@@ -172,20 +192,11 @@ inline int point_in_original(Point const& point, Original const& original)
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);
auto 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)
for (auto const& section : original.m_sections)
{
section_type const& section = *it;
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box)
@@ -207,32 +218,38 @@ inline int point_in_original(Point const& point, Original const& original)
}
template <typename Turns>
template <typename Turns, typename Strategy>
class turn_in_original_visitor
{
public:
turn_in_original_visitor(Turns& turns)
turn_in_original_visitor(Turns& turns, Strategy const& strategy)
: m_mutable_turns(turns)
, m_strategy(strategy)
{}
template <typename Turn, typename Original>
inline bool apply(Turn const& turn, Original const& original, bool first = true)
inline bool apply(Turn const& turn, Original const& original)
{
boost::ignore_unused(first);
if (boost::empty(original.m_ring))
{
// Skip empty rings
return true;
}
if (turn.location != location_ok || turn.within_original)
if (! turn.is_turn_traversable || turn.within_original)
{
// Skip all points already processed
return true;
}
if (geometry::disjoint(turn.robust_point, original.m_box))
if (geometry::disjoint(turn.point, original.m_box, m_strategy))
{
// Skip all disjoint
return true;
}
int const code = point_in_original(turn.robust_point, original);
int const code = point_in_original(turn.point, original,
m_strategy.relate(turn.point, original.m_ring));
if (code == -1)
{
@@ -244,7 +261,7 @@ public:
if (code == 0)
{
// On border of original: always discard
mutable_turn.location = location_discard;
mutable_turn.is_turn_traversable = false;
}
// Point is inside an original ring
@@ -269,6 +286,7 @@ public:
private :
Turns& m_mutable_turns;
Strategy const& m_strategy;
};

View File

@@ -1,792 +1,54 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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.
// This file was modified by Oracle on 2016-2022.
// Modifications copyright (c) 2016-2022 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
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#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/arithmetic/dot_product.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/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/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/strategies/cartesian/side_of_intersection.hpp>
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
#include <boost/geometry/geometries/box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
struct piece_get_box
{
template <typename Box, typename Piece>
static inline void apply(Box& total, Piece const& piece)
{
geometry::expand(total, piece.robust_envelope);
}
};
template <typename DisjointBoxBoxStrategy>
struct piece_ovelaps_box
{
template <typename Box, typename Piece>
static inline bool apply(Box const& box, Piece const& piece)
{
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;
}
return ! geometry::detail::disjoint::disjoint_box_box(box, piece.robust_envelope,
DisjointBoxBoxStrategy());
}
};
struct turn_get_box
{
template <typename Box, typename Turn>
static inline void apply(Box& total, Turn const& turn)
{
geometry::expand(total, turn.robust_point);
}
};
template <typename DisjointPointBoxStrategy>
struct turn_ovelaps_box
{
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)
{
return ! geometry::detail::disjoint::disjoint_point_box(turn.robust_point, box,
DisjointPointBoxStrategy());
}
};
enum analyse_result
{
analyse_unknown,
analyse_continue,
analyse_disjoint,
analyse_within,
analyse_on_original_boundary,
analyse_on_offsetted,
analyse_near_offsetted
};
template <typename Point>
inline bool in_box(Point const& previous,
Point const& current, Point const& point)
{
// Get its box (TODO: this can be prepared-on-demand later)
typedef geometry::model::box<Point> box_type;
box_type box;
geometry::assign_inverse(box);
geometry::expand(box, previous);
geometry::expand(box, current);
return geometry::covered_by(point, box);
}
// meta-programming-structure defining if to use side-of-intersection
// (only for cartesian / only necessary with rescaling)
template <typename Tag>
struct use_side_of_intersection {};
#if defined(BOOST_GEOMETRY_USE_RESCALING)
// With rescaling, let Cartesian use side-of-intersection
template <>
struct use_side_of_intersection<cartesian_tag> { static bool const value = true; };
#else
template <>
struct use_side_of_intersection<cartesian_tag> { static bool const value = false; };
#endif
template <>
struct use_side_of_intersection<spherical_tag> { static bool const value = false; };
template <>
struct use_side_of_intersection<geographic_tag> { static bool const value = false; };
template <bool UseSideOfIntersection>
struct check_segment {};
// Implementation using side-of-intersection
template <>
struct check_segment<true>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
segment_type const r(previous, current);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 0)
{
return analyse_on_offsetted;
}
if (side == -1 && from_monotonic)
{
return analyse_within;
}
if (side == 1 && from_monotonic)
{
return analyse_disjoint;
}
return analyse_continue;
}
};
template <>
struct check_segment<false>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& previous,
Point const& current, Turn const& turn,
bool from_monotonic)
{
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
int const side = side_strategy::apply(previous, current, turn.robust_point);
if (side == 0)
{
// Collinear, only on segment if it is covered by its bbox
if (in_box(previous, current, turn.robust_point))
{
return analyse_on_offsetted;
}
}
else if (side == -1)
{
// It is in the triangle right-of the segment where the
// segment is the hypothenusa. Check if it is close
// (within rounding-area)
if (in_box(previous, current, turn.robust_point))
{
return analyse_near_offsetted;
}
else if (from_monotonic)
{
return analyse_within;
}
}
else if (from_monotonic)
{
// Left of segment
return analyse_disjoint;
}
// Not monotonic, on left or right side: continue analysing
return analyse_continue;
}
};
template <bool UseSideOfIntersection>
class analyse_turn_wrt_point_piece {};
template <>
class analyse_turn_wrt_point_piece<true>
{
public :
template <typename Turn, typename Piece>
static inline analyse_result apply(Turn const& turn, Piece const& piece)
{
typedef typename Piece::section_type section_type;
typedef typename Turn::robust_point_type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
typedef geometry::model::referring_segment<point_type const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
coordinate_type const point_x = geometry::get<0>(turn.robust_point);
for (std::size_t s = 0; s < piece.sections.size(); s++)
{
section_type const& section = piece.sections[s];
// If point within horizontal range of monotonic section:
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
{
for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
{
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
// First check if it is in range - if it is not, the
// expensive side_of_intersection does not need to be
// applied
coordinate_type x1 = geometry::get<0>(previous);
coordinate_type x2 = geometry::get<0>(current);
if (x1 > x2)
{
std::swap(x1, x2);
}
if (point_x >= x1 - 1 && point_x <= x2 + 1)
{
segment_type const r(previous, current);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
// Sections are monotonic in x-dimension
if (side == 1)
{
// Left on segment
return analyse_disjoint;
}
else if (side == 0)
{
// Collinear - TODO: check if really on segment
return analyse_on_offsetted;
}
}
}
}
}
// It is nowhere outside, and not on segment, so it is within
return analyse_within;
}
};
template <>
class analyse_turn_wrt_point_piece<false>
{
public :
template <typename Turn, typename Piece>
static inline analyse_result apply(Turn const& turn, Piece const& piece)
{
typedef typename Piece::section_type section_type;
typedef typename Turn::robust_point_type point_type;
typedef typename geometry::coordinate_type<point_type>::type coordinate_type;
typedef strategy::within::winding<point_type> strategy_type;
typename strategy_type::state_type state;
strategy_type strategy;
BOOST_GEOMETRY_ASSERT(! piece.sections.empty());
coordinate_type const point_x = geometry::get<0>(turn.robust_point);
for (std::size_t s = 0; s < piece.sections.size(); s++)
{
section_type const& section = piece.sections[s];
// If point within horizontal range of monotonic section:
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box) - 1
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box) + 1)
{
for (signed_size_type i = section.begin_index + 1; i <= section.end_index; i++)
{
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
analyse_result code = check_segment<false>::apply(previous, current, turn, false);
if (code != analyse_continue)
{
return code;
}
// Get the state (to determine it is within), we don't have
// to cover the on-segment case (covered above)
strategy.apply(turn.robust_point, previous, current, state);
}
}
}
int const code = strategy.result(state);
if (code == 1)
{
return analyse_within;
}
else if (code == -1)
{
return analyse_disjoint;
}
// Should normally not occur - on-segment is covered
return analyse_unknown;
}
};
template <bool UseSideOfIntersection>
struct check_helper_segment {};
template <>
struct check_helper_segment<true>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& s1,
Point const& s2, Turn const& turn,
bool is_original,
Point const& offsetted)
{
boost::ignore_unused(offsetted);
boost::ignore_unused(is_original);
typedef geometry::model::referring_segment<Point const> segment_type;
segment_type const p(turn.rob_pi, turn.rob_pj);
segment_type const q(turn.rob_qi, turn.rob_qj);
segment_type const r(s1, s2);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 1)
{
// left of segment
return analyse_disjoint;
}
else if (side == 0)
{
// If is collinear, either on segment or before/after
typedef geometry::model::box<Point> box_type;
box_type box;
geometry::assign_inverse(box);
geometry::expand(box, s1);
geometry::expand(box, s2);
if (geometry::covered_by(turn.robust_point, box))
{
// Points on helper-segments (and not on its corners)
// are considered as within
return analyse_within;
}
// It is collinear but not on the segment. Because these
// segments are convex, it is outside
// Unless the offsetted ring is collinear or concave w.r.t.
// helper-segment but that scenario is not yet supported
return analyse_disjoint;
}
// right of segment
return analyse_continue;
}
};
template <>
struct check_helper_segment<false>
{
template <typename Point, typename Turn>
static inline analyse_result apply(Point const& s1,
Point const& s2, Turn const& turn,
bool is_original,
Point const& offsetted)
{
boost::ignore_unused(offsetted);
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<Point>::type
>::type side_strategy;
switch(side_strategy::apply(s1, s2, turn.robust_point))
{
case 1 :
return analyse_disjoint; // left of segment
case 0 :
{
// If is collinear, either on segment or before/after
typedef geometry::model::box<Point> box_type;
box_type box;
geometry::assign_inverse(box);
geometry::expand(box, s1);
geometry::expand(box, s2);
if (geometry::covered_by(turn.robust_point, box))
{
// It is on the segment
if (! is_original
&& geometry::comparable_distance(turn.robust_point, offsetted) <= 1)
{
// It is close to the offsetted-boundary, take
// any rounding-issues into account
return analyse_near_offsetted;
}
// Points on helper-segments are considered as within
// Points on original boundary are processed differently
return is_original
? analyse_on_original_boundary
: analyse_within;
}
// It is collinear but not on the segment. Because these
// segments are convex, it is outside
// Unless the offsetted ring is collinear or concave w.r.t.
// helper-segment but that scenario is not yet supported
return analyse_disjoint;
}
break;
}
// right of segment
return analyse_continue;
}
};
template <bool UseSideOfIntersection>
class analyse_turn_wrt_piece
{
template <typename Turn, typename Piece>
static inline analyse_result check_helper_segments(Turn const& turn, Piece const& piece)
{
typedef typename Turn::robust_point_type point_type;
geometry::equal_to<point_type> comparator;
point_type points[4];
signed_size_type helper_count = static_cast<signed_size_type>(piece.robust_ring.size())
- piece.offsetted_count;
if (helper_count == 4)
{
for (int i = 0; i < 4; i++)
{
points[i] = piece.robust_ring[piece.offsetted_count + i];
}
// 3--offsetted outline--0
// | |
// left | | right
// | |
// 2===>==original===>===1
}
else if (helper_count == 3)
{
// Triangular piece, assign points but assign second twice
for (int i = 0; i < 4; i++)
{
int index = i < 2 ? i : i - 1;
points[i] = piece.robust_ring[piece.offsetted_count + index];
}
}
else
{
// Some pieces (e.g. around points) do not have helper segments.
// Others should have 3 (join) or 4 (side)
return analyse_continue;
}
// First check point-equality
point_type const& point = turn.robust_point;
if (comparator(point, points[0]) || comparator(point, points[3]))
{
return analyse_on_offsetted;
}
if (comparator(point, points[1]))
{
// On original, right corner
return piece.is_flat_end ? analyse_continue : analyse_on_original_boundary;
}
if (comparator(point, points[2]))
{
// On original, left corner
return piece.is_flat_start ? analyse_continue : analyse_on_original_boundary;
}
// Right side of the piece
analyse_result result
= check_helper_segment<UseSideOfIntersection>::apply(points[0], points[1], turn,
false, points[0]);
if (result != analyse_continue)
{
return result;
}
// Left side of the piece
result = check_helper_segment<UseSideOfIntersection>::apply(points[2], points[3], turn,
false, points[3]);
if (result != analyse_continue)
{
return result;
}
if (! comparator(points[1], points[2]))
{
// Side of the piece at side of original geometry
result = check_helper_segment<UseSideOfIntersection>::apply(points[1], points[2], turn,
true, point);
if (result != analyse_continue)
{
return result;
}
}
// We are within the \/ or |_| shaped piece, where the top is the
// offsetted ring.
if (! geometry::covered_by(point, piece.robust_offsetted_envelope))
{
// Not in offsetted-area. This makes a cheap check possible
typedef typename strategy::side::services::default_strategy
<
typename cs_tag<point_type>::type
>::type side_strategy;
switch(side_strategy::apply(points[3], points[0], point))
{
case 1 : return analyse_disjoint;
case -1 : return analyse_within;
case 0 : return analyse_disjoint;
}
}
return analyse_continue;
}
template <typename Turn, typename Piece, typename Compare>
static inline analyse_result check_monotonic(Turn const& turn, Piece const& piece, Compare const& compare)
{
typedef typename Piece::piece_robust_ring_type ring_type;
typedef typename ring_type::const_iterator it_type;
it_type end = piece.robust_ring.begin() + piece.offsetted_count;
it_type it = std::lower_bound(piece.robust_ring.begin(),
end,
turn.robust_point,
compare);
if (it != end
&& it != piece.robust_ring.begin())
{
// iterator points to point larger than point
// w.r.t. specified direction, and prev points to a point smaller
// We now know if it is inside/outside
it_type prev = it - 1;
return check_segment<UseSideOfIntersection>::apply(*prev, *it, turn, true);
}
return analyse_continue;
}
public :
template <typename Turn, typename Piece>
static inline analyse_result apply(Turn const& turn, Piece const& piece)
{
typedef typename Turn::robust_point_type point_type;
analyse_result code = check_helper_segments(turn, piece);
if (code != analyse_continue)
{
return code;
}
geometry::equal_to<point_type> comparator;
if (piece.offsetted_count > 8)
{
// If the offset contains some points and is monotonic, we try
// to avoid walking all points linearly.
// We try it only once.
if (piece.is_monotonic_increasing[0])
{
code = check_monotonic(turn, piece, geometry::less<point_type, 0>());
if (code != analyse_continue) return code;
}
else if (piece.is_monotonic_increasing[1])
{
code = check_monotonic(turn, piece, geometry::less<point_type, 1>());
if (code != analyse_continue) return code;
}
else if (piece.is_monotonic_decreasing[0])
{
code = check_monotonic(turn, piece, geometry::greater<point_type, 0>());
if (code != analyse_continue) return code;
}
else if (piece.is_monotonic_decreasing[1])
{
code = check_monotonic(turn, piece, geometry::greater<point_type, 1>());
if (code != analyse_continue) return code;
}
}
// It is small or not monotonic, walk linearly through offset
// TODO: this will be combined with winding strategy
for (signed_size_type i = 1; i < piece.offsetted_count; i++)
{
point_type const& previous = piece.robust_ring[i - 1];
point_type const& current = piece.robust_ring[i];
// The robust ring can contain duplicates
// (on which any side or side-value would return 0)
if (! comparator(previous, current))
{
code = check_segment<UseSideOfIntersection>::apply(previous, current, turn, false);
if (code != analyse_continue)
{
return code;
}
}
}
return analyse_unknown;
}
};
// Helper Structure, of which the apply method returns a side value in {-1, 0, 1}
template <bool UseSideOfIntersection>
struct turn_in_piece {};
template <>
struct turn_in_piece<true>
{
private :
template <typename Turn, typename Piece>
static inline int in_convex_piece(Turn const& turn, Piece const& piece)
{
typedef typename Turn::robust_point_type point_type;
typedef typename Piece::piece_robust_ring_type ring_type;
typedef geometry::model::referring_segment<point_type const> segment;
segment const p(turn.rob_pi, turn.rob_pj);
segment const q(turn.rob_qi, turn.rob_qj);
typedef typename boost::range_iterator<ring_type const>::type iterator_type;
iterator_type it = boost::begin(piece.robust_ring);
iterator_type end = boost::end(piece.robust_ring);
// A robust ring is always closed, and always clockwise
for (iterator_type previous = it++; it != end; ++previous, ++it)
{
geometry::equal_to<point_type> comparator;
if (comparator(*previous, *it))
{
// Points are the same
continue;
}
segment r(*previous, *it);
int const side = strategy::side::side_of_intersection::apply(p, q, r,
turn.robust_point);
if (side == 1)
{
// IP is left of segment, so it is outside
return -1; // outside
}
else if (side == 0)
{
// IP is collinear with segment. TODO: we should analyze this further
// For now we use the fallback point
if (in_box(*previous, *it, turn.robust_point))
{
return 0;
}
else
{
return -1; // outside
}
}
}
return 1; // inside
}
public :
template <typename Turn, typename Piece, typename Strategy>
static inline int apply(Turn const& turn, Piece const& piece,
Strategy const& strategy)
{
if (piece.is_convex)
{
return in_convex_piece(turn, piece);
}
else
{
// side-of-intersection only supported for convex pieces
// Call point_in_geometry, a performance-bottleneck
// TODO: might be replaced by extending analysing piece
return detail::within::point_in_geometry(turn.robust_point,
piece.robust_ring, strategy);
}
}
};
template <>
struct turn_in_piece<false>
{
public :
template <typename Turn, typename Piece, typename Strategy>
static inline int apply(Turn const& turn, Piece const& piece,
Strategy const& strategy)
{
return detail::within::point_in_geometry(turn.robust_point,
piece.robust_ring, strategy);
}
};
template
<
typename CsTag,
typename Turns,
typename Pieces,
typename PointInGeometryStrategy
typename DistanceStrategy,
typename UmbrellaStrategy
>
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
PointInGeometryStrategy const& m_point_in_geometry_strategy;
DistanceStrategy const& m_distance_strategy; // to check if point is on original or one_sided
UmbrellaStrategy const& m_umbrella_strategy;
template <typename Operation, typename Piece>
inline bool skip(Operation const& op, Piece const& piece) const
@@ -815,24 +77,40 @@ class turn_in_piece_visitor
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,
PointInGeometryStrategy const& strategy)
DistanceStrategy const& distance_strategy,
UmbrellaStrategy const& umbrella_strategy)
: m_turns(turns)
, m_pieces(pieces)
, m_point_in_geometry_strategy(strategy)
, m_distance_strategy(distance_strategy)
, m_umbrella_strategy(umbrella_strategy)
{}
template <typename Turn, typename Piece>
inline bool apply(Turn const& turn, Piece const& piece, bool first = true)
inline bool apply(Turn const& turn, Piece const& piece)
{
boost::ignore_unused(first);
if (turn.count_within > 0)
if (! turn.is_turn_traversable)
{
// Already inside - no need to check again
// Already handled
return true;
}
@@ -843,78 +121,63 @@ public:
return true;
}
if (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
{
// Easy check: if the turn is not in the envelope, we can safely return
return true;
}
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
{
return true;
}
// TODO: mutable_piece to make some on-demand preparations in analyse
Turn& mutable_turn = m_turns[turn.turn_index];
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, m_umbrella_strategy))
{
// Easy check: if turn is not in the (expanded) envelope
return true;
}
if (piece.type == geometry::strategy::buffer::buffered_empty_side)
{
return false;
}
if (piece.type == geometry::strategy::buffer::buffered_point)
{
// Optimization for buffer around points: if distance from center
// is not between min/max radius, the result is clear
typedef typename default_comparable_distance_result
<
typename Turn::robust_point_type
>::type distance_type;
// 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.
auto const d = geometry::comparable_distance(piece.m_center, turn.point,
m_umbrella_strategy);
distance_type const cd
= geometry::comparable_distance(piece.robust_center,
turn.robust_point);
if (cd < piece.robust_min_comparable_radius)
if (d < border.m_min_comparable_radius)
{
mutable_turn.count_within++;
Turn& mutable_turn = m_turns[turn.turn_index];
mutable_turn.is_turn_traversable = false;
return true;
}
if (cd > piece.robust_max_comparable_radius)
if (d > border.m_max_comparable_radius)
{
return true;
}
}
static const bool use_soi = use_side_of_intersection<CsTag>::value;
boost::ignore_unused(use_soi);
// Check if buffer is one-sided (at this point), because then a point
// on the original border is not considered as within.
bool const one_sided = has_zero_distance_at(turn.point);
analyse_result analyse_code =
piece.type == geometry::strategy::buffer::buffered_point
? analyse_turn_wrt_point_piece<use_soi>::apply(turn, piece)
: analyse_turn_wrt_piece<use_soi>::apply(turn, piece);
switch(analyse_code)
typename Border::state_type state;
if (! border.point_on_piece(turn.point, one_sided,
turn.is_linear_end_point, state))
{
case analyse_disjoint :
return true;
case analyse_on_offsetted :
mutable_turn.count_on_offsetted++; // value is not used anymore
return true;
case analyse_on_original_boundary :
mutable_turn.count_on_original_boundary++;
return true;
case analyse_within :
mutable_turn.count_within++;
return true;
case analyse_near_offsetted :
mutable_turn.count_within_near_offsetted++;
return true;
default :
break;
return true;
}
int const geometry_code = turn_in_piece<use_soi>::apply(turn, piece,
m_point_in_geometry_strategy);
if (geometry_code == 1)
if (state.is_inside() && ! state.is_on_boundary())
{
mutable_turn.count_within++;
Turn& mutable_turn = m_turns[turn.turn_index];
mutable_turn.is_turn_traversable = false;
}
return true;
@@ -928,4 +191,4 @@ public:
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP

View File

@@ -0,0 +1,362 @@
// Boost.Geometry
// Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2019-2021, 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)
{}
decltype(auto) 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;
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
std::vector<clean_point_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)
{
auto it0 = cleaned.end() - 3;
auto it1 = cleaned.end() - 2;
auto 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
auto cleaned_b = cleaned.begin();
auto cleaned_e = cleaned.end();
std::size_t cleaned_count = cleaned.size();
bool found = false;
do
{
found = false;
while(cleaned_count >= 3)
{
auto it0 = cleaned_e - 2;
auto it1 = cleaned_e - 1;
auto it2 = cleaned_b;
auto 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 (auto it = cleaned_b; it != cleaned_e; ++it)
{
auto it0 = (it == cleaned_b ? cleaned_e - 1 : it - 1);
auto 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)
{
auto const result = detail::area::ring_area::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()));
decltype(result) 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 const>();
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 const>();
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

View File

@@ -8,9 +8,10 @@
// 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.
// Modifications copyright (c) 2016 Oracle and/or its affiliates.
// 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
@@ -19,7 +20,8 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
namespace boost { namespace geometry
{
@@ -35,8 +37,7 @@ class calculate_polygon_sum
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)
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
sum += Policy::apply(*it, strategy);
}

View File

@@ -75,7 +75,7 @@ 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)
{

View File

@@ -1,71 +0,0 @@
// 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

View File

@@ -92,7 +92,7 @@ public:
typename RangeIterator,
typename Strategy,
typename Distance
>
>
static inline RangeIterator apply(Geometry const& geometry,
RangeIterator first,
RangeIterator last,
@@ -111,7 +111,7 @@ public:
typename Geometry,
typename RangeIterator,
typename Strategy
>
>
static inline RangeIterator apply(Geometry const& geometry,
RangeIterator first,
RangeIterator last,

View File

@@ -1,8 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -12,7 +12,9 @@
#include <utility>
#include <boost/range.hpp>
#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>
@@ -34,15 +36,14 @@ template
<
typename Point,
typename Range,
closure_selector Closure,
typename Strategy
closure_selector Closure
>
class point_to_point_range
{
protected:
typedef typename boost::range_iterator<Range const>::type iterator_type;
template <typename Distance>
template <typename Strategy, typename Distance>
static inline void apply(Point const& point,
iterator_type first,
iterator_type last,
@@ -71,8 +72,11 @@ protected:
// check if other segments are closer
for (++prev, ++it; it != last; ++prev, ++it)
{
Distance dist = strategy.apply(point, *prev, *it);
if (geometry::math::equals(dist, zero))
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;
@@ -93,7 +97,7 @@ protected:
public:
typedef typename std::pair<iterator_type, iterator_type> return_type;
template <typename Distance>
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
@@ -106,6 +110,7 @@ public:
return std::make_pair(it_min1, it_min2);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
@@ -121,7 +126,7 @@ public:
return apply(point, first, last, strategy, dist_min);
}
template <typename Distance>
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy,
@@ -134,6 +139,7 @@ public:
dist_min);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy)
@@ -145,15 +151,15 @@ public:
// 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>
template <typename Point, typename Range>
class point_to_point_range<Point, Range, open>
: point_to_point_range<Point, Range, closed>
{
private:
typedef point_to_point_range<Point, Range, closed, Strategy> base_type;
typedef point_to_point_range<Point, Range, closed> base_type;
typedef typename base_type::iterator_type iterator_type;
template <typename Distance>
template <typename Strategy, typename Distance>
static inline void apply(Point const& point,
iterator_type first,
iterator_type last,
@@ -183,12 +189,12 @@ private:
it_min1 = it_back;
it_min2 = first;
}
}
}
public:
typedef typename std::pair<iterator_type, iterator_type> return_type;
template <typename Distance>
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
@@ -202,6 +208,7 @@ public:
return std::make_pair(it_min1, it_min2);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
@@ -219,7 +226,7 @@ public:
return apply(point, first, last, strategy, dist_min);
}
template <typename Distance>
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy,
@@ -232,6 +239,7 @@ public:
dist_min);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy)

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// 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
@@ -40,7 +41,7 @@ private:
<
typename RTreeRangeIterator,
typename QueryRangeIterator,
typename Strategy,
typename Strategies,
typename RTreeValueType,
typename Distance
>
@@ -48,12 +49,16 @@ private:
RTreeRangeIterator rtree_last,
QueryRangeIterator queries_first,
QueryRangeIterator queries_last,
Strategy const& strategy,
Strategies const& strategies,
RTreeValueType& rtree_min,
QueryRangeIterator& qit_min,
Distance& dist_min)
{
typedef index::rtree<RTreeValueType, index::linear<8> > rtree_type;
typedef index::parameters
<
index::linear<8>, Strategies
> 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 );
@@ -62,7 +67,8 @@ private:
dist_min = zero;
// create -- packing algorithm
rtree_type rt(rtree_first, rtree_last);
rtree_type rt(rtree_first, rtree_last,
index_parameters_type(index::linear<8>(), strategies));
RTreeValueType t_v;
bool first = true;
@@ -88,8 +94,8 @@ private:
<
QueryRangeIterator
>::value_type,
Strategy
>::apply(t_v, *qit, strategy);
Strategies
>::apply(t_v, *qit, strategies);
if (first || dist < dist_min)
{
@@ -144,7 +150,7 @@ public:
apply(rtree_first, rtree_last, queries_first, queries_last,
strategy, rtree_min, qit_min, dist_min);
return std::make_pair(rtree_min, qit_min);
return std::make_pair(rtree_min, qit_min);
}

View File

@@ -0,0 +1,28 @@
// Boost.Geometry
// Copyright (c) 2021, 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_CLOSEST_POINTS_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_IMPLEMENTATION_HPP
#include <boost/geometry/algorithms/detail/distance/implementation.hpp>
#include <boost/geometry/algorithms/detail/closest_points/point_to_geometry.hpp>
#include <boost/geometry/algorithms/detail/closest_points/multipoint_to_geometry.hpp>
#include <boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp>
#include <boost/geometry/algorithms/detail/closest_points/linear_or_areal_to_areal.hpp>
//#include <boost/geometry/algorithms/detail/closest_points/linear_to_box.hpp>
//#include <boost/geometry/algorithms/detail/closest_points/geometry_to_segment_or_box.hpp>
#include <boost/geometry/algorithms/detail/closest_points/segment_to_segment.hpp>
//#include <boost/geometry/algorithms/detail/closest_points/segment_to_box.hpp>
//#include <boost/geometry/algorithms/detail/closest_points/box_to_box.hpp>
#include <boost/geometry/strategies/closest_points/cartesian.hpp>
#include <boost/geometry/strategies/closest_points/geographic.hpp>
#include <boost/geometry/strategies/closest_points/spherical.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_IMPLEMENTATION_HPP

View File

@@ -0,0 +1,225 @@
// Boost.Geometry
// Copyright (c) 2021, 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_CLOSEST_POINTS_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_INTERFACE_HPP
#include <boost/concept_check.hpp>
#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/dispatch/closest_points.hpp>
#include <boost/geometry/algorithms/detail/distance/interface.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/closest_points/services.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// If reversal is needed, perform it
template
<
typename Geometry1,
typename Geometry2,
typename Tag1,
typename Tag2
>
struct closest_points
<
Geometry1, Geometry2,
Tag1, Tag2, true
>
: closest_points<Geometry2, Geometry1, Tag2, Tag1, false>
{
template <typename Segment, typename Strategy>
static inline void apply(Geometry1 const& g1, Geometry2 const& g2,
Segment& shortest_seg, Strategy const& strategy)
{
closest_points
<
Geometry2, Geometry1, Tag2, Tag1, false
>::apply(g2, g1, shortest_seg, strategy);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template<typename Strategy>
struct closest_points
{
template <typename Geometry1, typename Geometry2, typename Segment>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Segment& shortest_seg,
Strategy const& strategy)
{
dispatch::closest_points
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, shortest_seg, strategy);
}
};
template <>
struct closest_points<default_strategy>
{
template <typename Geometry1, typename Geometry2, typename Segment>
static inline void
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Segment& shortest_seg,
default_strategy)
{
using strategy_type = typename strategies::closest_points::services::default_strategy
<
Geometry1, Geometry2
>::type;
dispatch::closest_points
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, shortest_seg, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
struct closest_points
{
template <typename Segment, typename Strategy>
static inline void apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Segment& shortest_seg,
Strategy const& strategy)
{
resolve_strategy::closest_points
<
Strategy
>::apply(geometry1, geometry2, shortest_seg, strategy);
}
};
//TODO: Add support for DG/GC
} // namespace resolve_variant
/*!
\brief Calculate the closest points between two geometries \brief_strategy
\ingroup closest_points
\details
\details The free function closest_points calculates the distance between two geometries \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Segment Any type fulfilling a Segment Concept
\tparam Strategy \tparam_strategy{Closest Points}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param shortest_seg Output segment containing the closest points
\param strategy \param_strategy{closest_points}
\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 Example]
[closest_points_strategy]
[closest_points_strategy_output]
[heading See also]
\* [link geometry.reference.algorithms.distance distance]
}
*/
template <typename Geometry1, typename Geometry2, typename Segment, typename Strategy>
inline void closest_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Segment& shortest_seg,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
detail::throw_on_empty_input(geometry1);
detail::throw_on_empty_input(geometry2);
resolve_variant::closest_points
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, shortest_seg, strategy);
}
/*!
\brief Compute the closest points between two geometries.
\ingroup closest_points
\details The free function closest_points calculates the closest points between two geometries. \details_default_strategy
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Segment Any type fulfilling a Segment Concept
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param shortest_seg Output segment containing the closest points
\qbk{
[heading Example]
[closest_points]
[closest_points_output]
[heading See also]
\* [link geometry.reference.algorithms.distance distance]
}
*/
template <typename Geometry1, typename Geometry2, typename Segment>
inline void closest_points(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Segment& shortest_seg)
{
closest_points(geometry1, geometry2, shortest_seg, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_INTERFACE_HPP

View File

@@ -0,0 +1,261 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2021, 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_CLOSEST_POINTS_LINEAR_OR_AREAL_TO_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_OR_AREAL_TO_AREAL_HPP
#include <boost/geometry/algorithms/detail/closest_points/linear_to_linear.hpp>
#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/geometries/geometries.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_points
{
struct linear_to_areal
{
template <typename Linear, typename Areal, typename Segment, typename Strategies>
static inline void apply(Linear const& linear,
Areal const& areal,
Segment& shortest_seg,
Strategies const& strategies)
{
using most_precise_type = typename select_coordinate_type<Linear, Areal>::type;
using point_type = typename std::conditional
<
std::is_same<typename coordinate_type<Linear>::type, most_precise_type>::value,
typename point_type<Linear>::type,
typename point_type<Areal>::type
>::type;
using linestring_type = geometry::model::linestring<point_type>;
/* TODO: currently intersection does not support some cases of tupled input
* such as linestring - multipolygon
* this could be implemented directly with dynamic geometries
using polygon_type = geometry::model::polygon<point_type>;
std::tuple
<
geometry::model::multi_point<point_type>,
geometry::model::multi_linestring<linestring_type>,
geometry::model::multi_polygon<polygon_type>
> tp;
bool intersect_tp = geometry::intersection(linear, areal, tp, strategies);
*/
geometry::model::multi_point<point_type> mp_out;
geometry::intersection(linear, areal, mp_out, strategies);
if (! boost::empty(mp_out))
{
set_segment_from_points::apply(*boost::begin(mp_out),
*boost::begin(mp_out),
shortest_seg);
return;
}
// if there are no intersection points then check if the linear geometry
// (or part of it) is inside the areal and return any point of this part
geometry::model::multi_linestring<linestring_type> ln_out;
geometry::intersection(linear, areal, ln_out, strategies);
if (! boost::empty(ln_out))
{
set_segment_from_points::apply(*boost::begin(*boost::begin(ln_out)),
*boost::begin(*boost::begin(ln_out)),
shortest_seg);
return;
}
linear_to_linear::apply(linear, areal, shortest_seg, strategies, false);
}
};
struct areal_to_linear
{
template <typename Linear, typename Areal, typename Segment, typename Strategies>
static inline void apply(Areal const& areal,
Linear const& linear,
Segment& shortest_seg,
Strategies const& strategies)
{
linear_to_areal::apply(linear, areal, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
struct segment_to_areal
{
template <typename Segment, typename Areal, typename OutSegment, typename Strategies>
static inline void apply(Segment const& segment,
Areal const& areal,
OutSegment& shortest_seg,
Strategies const& strategies,
bool = false)
{
using linestring_type = geometry::model::linestring<typename point_type<Segment>::type>;
linestring_type linestring;
convert(segment, linestring);
linear_to_areal::apply(linestring, areal, shortest_seg, strategies);
}
};
struct areal_to_segment
{
template <typename Areal, typename Segment, typename OutSegment, typename Strategies>
static inline void apply(Areal const& areal,
Segment const& segment,
OutSegment& shortest_seg,
Strategies const& strategies,
bool = false)
{
segment_to_areal::apply(segment, areal, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
struct areal_to_areal
{
template <typename Areal1, typename Areal2, typename Segment, typename Strategies>
static inline void apply(Areal1 const& areal1,
Areal2 const& areal2,
Segment& shortest_seg,
Strategies const& strategies)
{
using most_precise_type = typename select_coordinate_type<Areal1, Areal2>::type;
using point_type = typename std::conditional
<
std::is_same<typename coordinate_type<Areal1>::type, most_precise_type>::value,
typename point_type<Areal1>::type,
typename point_type<Areal2>::type
>::type;
using linestring_type = geometry::model::linestring<point_type>;
using polygon_type = geometry::model::polygon<point_type>;
/* TODO: currently intersection does not support tupled input
* this should be implemented directly with dynamic geometries
*/
geometry::model::multi_point<point_type> mp_out;
geometry::intersection(areal1, areal2, mp_out, strategies);
if (! boost::empty(mp_out))
{
set_segment_from_points::apply(*boost::begin(mp_out),
*boost::begin(mp_out),
shortest_seg);
return;
}
// if there are no intersection points then the linear geometry (or part of it)
// is inside the areal; return any point of this part
geometry::model::multi_linestring<linestring_type> ln_out;
geometry::intersection(areal1, areal2, ln_out, strategies);
if (! boost::empty(ln_out))
{
set_segment_from_points::apply(*boost::begin(*boost::begin(ln_out)),
*boost::begin(*boost::begin(ln_out)),
shortest_seg);
return;
}
geometry::model::multi_polygon<polygon_type> pl_out;
geometry::intersection(areal1, areal2, pl_out, strategies);
if (! boost::empty(pl_out))
{
set_segment_from_points::apply(
*boost::begin(boost::geometry::exterior_ring(*boost::begin(pl_out))),
*boost::begin(boost::geometry::exterior_ring(*boost::begin(pl_out))),
shortest_seg);
return;
}
linear_to_linear::apply(areal1, areal2, shortest_seg, strategies, false);
}
};
}} // namespace detail::closest_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Areal>
struct closest_points
<
Linear, Areal,
linear_tag, areal_tag,
false
>
: detail::closest_points::linear_to_areal
{};
template <typename Areal, typename Linear>
struct closest_points
<
Areal, Linear,
areal_tag, linear_tag,
false
>
: detail::closest_points::areal_to_linear
{};
template <typename Segment, typename Areal>
struct closest_points
<
Segment, Areal,
segment_tag, areal_tag,
false
>
: detail::closest_points::segment_to_areal
{};
template <typename Areal, typename Segment>
struct closest_points
<
Areal, Segment,
areal_tag, segment_tag,
false
>
: detail::closest_points::areal_to_segment
{};
template <typename Areal1, typename Areal2>
struct closest_points
<
Areal1, Areal2,
areal_tag, areal_tag,
false
>
: detail::closest_points::areal_to_areal
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_OR_AREAL_TO_AREAL_HPP

View File

@@ -0,0 +1,155 @@
// Boost.Geometry
// Copyright (c) 2021, 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_CLOSEST_POINTS_LINEAR_TO_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_TO_LINEAR_HPP
#include <boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp>
#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/num_segments.hpp>
#include <boost/geometry/core/point_type.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 closest_points
{
struct linear_to_linear
{
template <typename Linear1, typename Linear2, typename Segment, typename Strategies>
static inline void apply(Linear1 const& linear1,
Linear2 const& linear2,
Segment& shortest_seg,
Strategies const& strategies,
bool = false)
{
if (geometry::num_points(linear1) == 1)
{
dispatch::closest_points
<
typename point_type<Linear1>::type,
Linear2
>::apply(*points_begin(linear1), linear2, shortest_seg, strategies);
return;
}
if (geometry::num_points(linear2) == 1)
{
dispatch::closest_points
<
typename point_type<Linear2>::type,
Linear1
>::apply(*points_begin(linear2), linear1, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
return;
}
if (geometry::num_segments(linear1) < geometry::num_segments(linear2))
{
point_or_segment_range_to_geometry_rtree::apply(
geometry::segments_begin(linear2),
geometry::segments_end(linear2),
linear1,
shortest_seg,
strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
return;
}
point_or_segment_range_to_geometry_rtree::apply(
geometry::segments_begin(linear1),
geometry::segments_end(linear1),
linear2,
shortest_seg,
strategies);
}
};
struct segment_to_linear
{
template <typename Segment, typename Linear, typename OutSegment, typename Strategies>
static inline void apply(Segment const& segment,
Linear const& linear,
OutSegment& shortest_seg,
Strategies const& strategies,
bool = false)
{
using linestring_type = geometry::model::linestring
<typename point_type<Segment>::type>;
linestring_type linestring;
convert(segment, linestring);
linear_to_linear::apply(linestring, linear, shortest_seg, strategies);
}
};
struct linear_to_segment
{
template <typename Linear, typename Segment, typename OutSegment, typename Strategies>
static inline void apply(Linear const& linear,
Segment const& segment,
OutSegment& shortest_seg,
Strategies const& strategies,
bool = false)
{
segment_to_linear::apply(segment, linear, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
}} // namespace detail::closest_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear1, typename Linear2>
struct closest_points
<
Linear1, Linear2,
linear_tag, linear_tag,
false
> : detail::closest_points::linear_to_linear
{};
template <typename Segment, typename Linear>
struct closest_points
<
Segment, Linear,
segment_tag, linear_tag,
false
> : detail::closest_points::segment_to_linear
{};
template <typename Linear, typename Segment>
struct closest_points
<
Linear, Segment,
linear_tag, segment_tag,
false
> : detail::closest_points::linear_to_segment
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_LINEAR_TO_LINEAR_HPP

View File

@@ -0,0 +1,325 @@
// Boost.Geometry
// Copyright (c) 2021, 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_CLOSEST_POINTS_MULTIPOINT_TO_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_MULTIPOINT_TO_GEOMETRY_HPP
#include <iterator>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/closest_points/range_to_geometry_rtree.hpp>
#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/dispatch/closest_points.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/linestring.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_points
{
struct multipoint_to_multipoint
{
template
<
typename MultiPoint1,
typename MultiPoint2,
typename Segment,
typename Strategies
>
static inline void apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
Segment& shortest_seg,
Strategies const& strategies)
{
if (boost::size(multipoint1) < boost::size(multipoint2))
{
point_or_segment_range_to_geometry_rtree::apply(
boost::begin(multipoint2),
boost::end(multipoint2),
multipoint1,
shortest_seg,
strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
return;
}
point_or_segment_range_to_geometry_rtree::apply(
boost::begin(multipoint1),
boost::end(multipoint1),
multipoint2,
shortest_seg,
strategies);
}
};
struct multipoint_to_linear
{
template
<
typename MultiPoint,
typename Linear,
typename Segment,
typename Strategies
>
static inline void apply(MultiPoint const& multipoint,
Linear const& linear,
Segment& shortest_seg,
Strategies const& strategies)
{
point_or_segment_range_to_geometry_rtree::apply(
boost::begin(multipoint),
boost::end(multipoint),
linear,
shortest_seg,
strategies);
}
};
struct linear_to_multipoint
{
template
<
typename Linear,
typename MultiPoint,
typename Segment,
typename Strategies
>
static inline void apply(Linear const& linear,
MultiPoint const& multipoint,
Segment& shortest_seg,
Strategies const& strategies)
{
multipoint_to_linear::apply(multipoint, linear, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
struct segment_to_multipoint
{
template
<
typename Segment,
typename MultiPoint,
typename OutSegment,
typename Strategies
>
static inline void apply(Segment const& segment,
MultiPoint const& multipoint,
OutSegment& shortest_seg,
Strategies const& strategies)
{
using linestring_type = geometry::model::linestring
<
typename point_type<Segment>::type
>;
linestring_type linestring;
convert(segment, linestring);
multipoint_to_linear::apply(multipoint, linestring, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
struct multipoint_to_segment
{
template
<
typename MultiPoint,
typename Segment,
typename OutSegment,
typename Strategies
>
static inline void apply(MultiPoint const& multipoint,
Segment const& segment,
OutSegment& shortest_seg,
Strategies const& strategies)
{
using linestring_type = geometry::model::linestring
<
typename point_type<Segment>::type
>;
linestring_type linestring;
convert(segment, linestring);
multipoint_to_linear::apply(multipoint, linestring, shortest_seg,
strategies);
}
};
struct multipoint_to_areal
{
private:
template <typename Areal, typename Strategies>
struct covered_by_areal
{
covered_by_areal(Areal const& areal, Strategies const& strategy)
: m_areal(areal), m_strategy(strategy)
{}
template <typename Point>
inline bool operator()(Point const& point) const
{
return geometry::covered_by(point, m_areal, m_strategy);
}
Areal const& m_areal;
Strategies const& m_strategy;
};
public:
template
<
typename MultiPoint,
typename Areal,
typename Segment,
typename Strategies
>
static inline void apply(MultiPoint const& multipoint,
Areal const& areal,
Segment& shortest_seg,
Strategies const& strategies)
{
covered_by_areal<Areal, Strategies> predicate(areal, strategies);
auto it = std::find_if(
boost::begin(multipoint),
boost::end(multipoint),
predicate);
if (it != boost::end(multipoint))
{
return set_segment_from_points::apply(*it, *it, shortest_seg);
}
point_or_segment_range_to_geometry_rtree::apply(
boost::begin(multipoint),
boost::end(multipoint),
areal,
shortest_seg,
strategies);
}
};
struct areal_to_multipoint
{
template
<
typename Areal,
typename MultiPoint,
typename Segment,
typename Strategies
>
static inline void apply(Areal const& areal,
MultiPoint const& multipoint,
Segment& shortest_seg,
Strategies const& strategies)
{
multipoint_to_areal::apply(multipoint, areal, shortest_seg, strategies);
detail::closest_points::swap_segment_points::apply(shortest_seg);
}
};
}} // namespace detail::closest_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename MultiPoint1, typename MultiPoint2>
struct closest_points
<
MultiPoint1, MultiPoint2,
multi_point_tag, multi_point_tag,
false
> : detail::closest_points::multipoint_to_multipoint
{};
template <typename MultiPoint, typename Linear>
struct closest_points
<
MultiPoint, Linear,
multi_point_tag, linear_tag,
false
> : detail::closest_points::multipoint_to_linear
{};
template <typename Linear, typename MultiPoint>
struct closest_points
<
Linear, MultiPoint,
linear_tag, multi_point_tag,
false
> : detail::closest_points::linear_to_multipoint
{};
template <typename MultiPoint, typename Segment>
struct closest_points
<
MultiPoint, Segment,
multi_point_tag, segment_tag,
false
> : detail::closest_points::multipoint_to_segment
{};
template <typename Segment, typename MultiPoint>
struct closest_points
<
Segment, MultiPoint,
segment_tag, multi_point_tag,
false
> : detail::closest_points::segment_to_multipoint
{};
template <typename MultiPoint, typename Areal>
struct closest_points
<
MultiPoint, Areal,
multi_point_tag, areal_tag,
false
> : detail::closest_points::multipoint_to_areal
{};
template <typename Areal, typename MultiPoint>
struct closest_points
<
Areal, MultiPoint,
areal_tag, multi_point_tag,
false
> : detail::closest_points::areal_to_multipoint
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_MULTIPOINT_TO_GEOMETRY_HPP

View File

@@ -0,0 +1,456 @@
// Boost.Geometry
// Copyright (c) 2021-2023, 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_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_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/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/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
#include <boost/geometry/algorithms/dispatch/closest_points.hpp>
#include <boost/geometry/algorithms/dispatch/distance.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/radian_access.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/relate/services.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_points
{
struct point_to_point
{
template <typename P1, typename P2, typename Segment, typename Strategies>
static inline void apply(P1 const& p1, P2 const& p2,
Segment& shortest_seg, Strategies const&)
{
set_segment_from_points::apply(p1, p2, shortest_seg);
}
};
struct point_to_segment
{
template <typename Point, typename Segment, typename OutputSegment, typename Strategies>
static inline void apply(Point const& point, Segment const& segment,
OutputSegment& shortest_seg, Strategies const& strategies)
{
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(strategies);
auto closest_point = strategies.closest_points(point, segment)
.apply(point, p[0], p[1]);
set_segment_from_points::apply(point, closest_point, shortest_seg);
}
};
/*
struct point_to_box
{
template<typename Point, typename Box, typename Strategies>
static inline auto apply(Point const& point, Box const& box,
Strategies const& strategies)
{
boost::ignore_unused(strategies);
return strategies.closest_points(point, box).apply(point, box);
}
};
*/
template <closure_selector Closure>
class point_to_range
{
public:
template <typename Point, typename Range, typename Segment, typename Strategies>
static inline void apply(Point const& point, Range const& range,
Segment& shortest_seg,
Strategies const& strategies)
{
using point_to_point_range = detail::closest_feature::point_to_point_range
<
Point, Range, Closure
>;
if (boost::size(range) == 0)
{
set_segment_from_points::apply(point, point, shortest_seg);
return;
}
closest_points::creturn_t<Point, Range, Strategies> cd_min;
auto comparable_distance = strategy::distance::services::get_comparable
<
decltype(strategies.distance(point, range))
>::apply(strategies.distance(point, range));
auto closest_segment = point_to_point_range::apply(point,
boost::begin(range),
boost::end(range),
comparable_distance,
cd_min);
auto closest_point = strategies.closest_points(point, range)
.apply(point, *closest_segment.first, *closest_segment.second);
set_segment_from_points::apply(point, closest_point, shortest_seg);
}
};
template<closure_selector Closure>
struct point_to_ring
{
template <typename Point, typename Ring, typename Segment, typename Strategies>
static inline auto apply(Point const& point,
Ring const& ring,
Segment& shortest_seg,
Strategies const& strategies)
{
if (within::within_point_geometry(point, ring, strategies))
{
set_segment_from_points::apply(point, point, shortest_seg);
}
else
{
point_to_range
<
closure<Ring>::value
>::apply(point, ring, shortest_seg, strategies);
}
}
};
template <closure_selector Closure>
class point_to_polygon
{
template <typename Polygon>
struct distance_to_interior_rings
{
template
<
typename Point,
typename InteriorRingIterator,
typename Segment,
typename Strategies
>
static inline void apply(Point const& point,
InteriorRingIterator first,
InteriorRingIterator last,
Segment& shortest_seg,
Strategies const& strategies)
{
using per_ring = point_to_range<Closure>;
for (InteriorRingIterator it = first; it != last; ++it)
{
if (within::within_point_geometry(point, *it, strategies))
{
// the point is inside a polygon hole, so its distance
// to the polygon is its distance to the polygon's
// hole boundary
per_ring::apply(point, *it, shortest_seg, strategies);
return;
}
}
set_segment_from_points::apply(point, point, shortest_seg);
}
template
<
typename Point,
typename InteriorRings,
typename Segment,
typename Strategies
>
static inline void apply(Point const& point, InteriorRings const& interior_rings,
Segment& shortest_seg, Strategies const& strategies)
{
apply(point,
boost::begin(interior_rings),
boost::end(interior_rings),
shortest_seg,
strategies);
}
};
public:
template
<
typename Point,
typename Polygon,
typename Segment,
typename Strategies
>
static inline void apply(Point const& point,
Polygon const& polygon,
Segment& shortest_seg,
Strategies const& strategies)
{
using per_ring = point_to_range<Closure>;
if (! within::covered_by_point_geometry(point, exterior_ring(polygon),
strategies))
{
// the point is outside the exterior ring, so its distance
// to the polygon is its distance to the polygon's exterior ring
per_ring::apply(point, exterior_ring(polygon), shortest_seg, strategies);
return;
}
// Check interior rings
distance_to_interior_rings<Polygon>::apply(point,
interior_rings(polygon),
shortest_seg,
strategies);
}
};
template
<
typename MultiGeometry,
bool CheckCoveredBy = std::is_same
<
typename tag<MultiGeometry>::type, multi_polygon_tag
>::value
>
class point_to_multigeometry
{
private:
using geometry_to_range = detail::closest_feature::geometry_to_range;
public:
template
<
typename Point,
typename Segment,
typename Strategies
>
static inline void apply(Point const& point,
MultiGeometry const& multigeometry,
Segment& shortest_seg,
Strategies const& strategies)
{
using selector_type = distance::iterator_selector<MultiGeometry const>;
closest_points::creturn_t<Point, MultiGeometry, Strategies> cd;
auto comparable_distance = strategy::distance::services::get_comparable
<
decltype(strategies.distance(point, multigeometry))
>::apply(strategies.distance(point, multigeometry));
typename selector_type::iterator_type it_min
= geometry_to_range::apply(point,
selector_type::begin(multigeometry),
selector_type::end(multigeometry),
comparable_distance,
cd);
dispatch::closest_points
<
Point,
typename std::iterator_traits
<
typename selector_type::iterator_type
>::value_type
>::apply(point, *it_min, shortest_seg, strategies);
}
};
// this is called only for multipolygons, hence the change in the
// template parameter name MultiGeometry to MultiPolygon
template <typename MultiPolygon>
struct point_to_multigeometry<MultiPolygon, true>
{
template
<
typename Point,
typename Segment,
typename Strategies
>
static inline void apply(Point const& point,
MultiPolygon const& multipolygon,
Segment& shortest_seg,
Strategies const& strategies)
{
if (within::covered_by_point_geometry(point, multipolygon, strategies))
{
set_segment_from_points::apply(point, point, shortest_seg);
return;
}
return point_to_multigeometry
<
MultiPolygon, false
>::apply(point, multipolygon, shortest_seg, strategies);
}
};
}} // namespace detail::closest_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename P1, typename P2>
struct closest_points
<
P1, P2, point_tag, point_tag, false
> : detail::closest_points::point_to_point
{};
template <typename Point, typename Linestring>
struct closest_points
<
Point, Linestring, point_tag, linestring_tag, false
> : detail::closest_points::point_to_range<closed>
{};
template <typename Point, typename Ring>
struct closest_points
<
Point, Ring, point_tag, ring_tag, false
> : detail::closest_points::point_to_ring
<
closure<Ring>::value
>
{};
template <typename Point, typename Polygon>
struct closest_points
<
Point, Polygon, point_tag, polygon_tag, false
> : detail::closest_points::point_to_polygon
<
closure<Polygon>::value
>
{};
template <typename Point, typename Segment>
struct closest_points
<
Point, Segment, point_tag, segment_tag, false
> : detail::closest_points::point_to_segment
{};
/*
template <typename Point, typename Box>
struct closest_points
<
Point, Box, point_tag, box_tag,
strategy_tag_distance_point_box, false
> : detail::closest_points::point_to_box<Point, Box>
{};
*/
template<typename Point, typename MultiPoint>
struct closest_points
<
Point, MultiPoint, point_tag, multi_point_tag, false
> : detail::closest_points::point_to_multigeometry<MultiPoint>
{};
template<typename Point, typename MultiLinestring>
struct closest_points
<
Point, MultiLinestring, point_tag, multi_linestring_tag, false
> : detail::closest_points::point_to_multigeometry<MultiLinestring>
{};
template<typename Point, typename MultiPolygon>
struct closest_points
<
Point, MultiPolygon, point_tag, multi_polygon_tag, false
> : detail::closest_points::point_to_multigeometry<MultiPolygon>
{};
template <typename Point, typename Linear>
struct closest_points
<
Point, Linear, point_tag, linear_tag, false
> : closest_points
<
Point, Linear,
point_tag, typename tag<Linear>::type, false
>
{};
template <typename Point, typename Areal>
struct closest_points
<
Point, Areal, point_tag, areal_tag, false
> : closest_points
<
Point, Areal,
point_tag, typename tag<Areal>::type, false
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_POINT_TO_GEOMETRY_HPP

View File

@@ -0,0 +1,110 @@
// Boost.Geometry
// Copyright (c) 2021-2023, 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_CLOSEST_POINTS_RANGE_TO_GEOMETRY_RTREE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_RANGE_TO_GEOMETRY_RTREE_HPP
#include <iterator>
#include <utility>
#include <boost/geometry/algorithms/detail/closest_feature/range_to_range.hpp>
#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/iterator_selector.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/closest_points.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/iterators/detail/has_one_element.hpp>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_points
{
class point_or_segment_range_to_geometry_rtree
{
public:
template
<
typename PointOrSegmentIterator,
typename Geometry,
typename Segment,
typename Strategies
>
static inline void apply(PointOrSegmentIterator first,
PointOrSegmentIterator last,
Geometry const& geometry,
Segment& shortest_seg,
Strategies const& strategies)
{
typedef typename std::iterator_traits
<
PointOrSegmentIterator
>::value_type point_or_segment_type;
typedef distance::iterator_selector<Geometry const> selector_type;
typedef detail::closest_feature::range_to_range_rtree range_to_range;
BOOST_GEOMETRY_ASSERT( first != last );
//TODO: Is this special case needed?
//if ( detail::has_one_element(first, last) )
//{
// dispatch::closest_points
// <
// point_or_segment_type, Geometry
// >::apply(*first, geometry, shortest_seg, strategies);
//}
closest_points::creturn_t<point_or_segment_type, Geometry, Strategies> cd;
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),
strategies,
cd);
dispatch::closest_points
<
point_or_segment_type,
typename std::iterator_traits
<
typename selector_type::iterator_type
>::value_type
>::apply(closest_features.first,
*closest_features.second,
shortest_seg,
strategies);
}
};
}} // namespace detail::closest_points
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_RANGE_TO_GEOMETRY_RTREE_HPP

View File

@@ -0,0 +1,145 @@
// Boost.Geometry
// Copyright (c) 2021-2023, 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_CLOSEST_POINTS_SEGMENT_TO_SEGMENT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_SEGMENT_TO_SEGMENT_HPP
#include <algorithm>
#include <iterator>
#include <boost/core/addressof.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/closest_points/utilities.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/closest_points.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/intersects.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/util/condition.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_points
{
// compute segment-segment closest-points
class segment_to_segment
{
public:
template <typename Segment1, typename Segment2, typename OutputSegment, typename Strategies>
static inline void apply(Segment1 const& segment1, Segment2 const& segment2,
OutputSegment& shortest_seg,
Strategies const& strategies)
{
using intersection_return_type = segment_intersection_points
<
typename point_type<Segment1>::type
>;
using intersection_policy = policies::relate::segments_intersection_points
<
intersection_return_type
>;
detail::segment_as_subrange<Segment1> sub_range1(segment1);
detail::segment_as_subrange<Segment2> sub_range2(segment2);
auto is = strategies.relate().apply(sub_range1, sub_range2,
intersection_policy());
if (is.count > 0)
{
set_segment_from_points::apply(is.intersections[0],
is.intersections[0],
shortest_seg);
return;
}
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]);
auto cp0 = strategies.closest_points(q[0], segment1).apply(q[0], p[0], p[1]);
auto cp1 = strategies.closest_points(q[1], segment1).apply(q[1], p[0], p[1]);
auto cp2 = strategies.closest_points(p[0], segment2).apply(p[0], q[0], q[1]);
auto cp3 = strategies.closest_points(p[1], segment2).apply(p[1], q[0], q[1]);
closest_points::creturn_t<Segment1, Segment2, Strategies> d[4];
auto const cds = strategies::distance::detail::make_comparable(strategies)
.distance(detail::dummy_point(), detail::dummy_point());
d[0] = cds.apply(cp0, q[0]);
d[1] = cds.apply(cp1, q[1]);
d[2] = cds.apply(p[0], cp2);
d[3] = cds.apply(p[1], cp3);
std::size_t imin = std::distance(boost::addressof(d[0]), std::min_element(d, d + 4));
switch (imin)
{
case 0:
set_segment_from_points::apply(cp0, q[0], shortest_seg);
return;
case 1:
set_segment_from_points::apply(cp1, q[1], shortest_seg);
return;
case 2:
set_segment_from_points::apply(p[0], cp2, shortest_seg);
return;
default:
set_segment_from_points::apply(p[1], cp3, shortest_seg);
return;
}
}
};
}} // namespace detail::closest_points
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// segment-segment
template <typename Segment1, typename Segment2>
struct closest_points
<
Segment1, Segment2, segment_tag, segment_tag, false
> : detail::closest_points::segment_to_segment
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_SEGMENT_TO_SEGMENT_HPP

View File

@@ -0,0 +1,69 @@
// Boost.Geometry
// Copyright (c) 2021-2023, 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_CLOSEST_POINTS_UTILITIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_UTILITIES_HPP
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/util/algorithm.hpp>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace closest_points
{
struct set_segment_from_points
{
template <typename Point1, typename Point2, typename Segment>
static inline void apply(Point1 const& p1, Point2 const& p2, Segment& segment)
{
assign_point_to_index<0>(p1, segment);
assign_point_to_index<1>(p2, segment);
}
};
struct swap_segment_points
{
template <typename Segment>
static inline void apply(Segment& segment)
{
geometry::detail::for_each_dimension<Segment>([&](auto index)
{
auto temp = get<0,index>(segment);
set<0,index>(segment, get<1,index>(segment));
set<1,index>(segment, temp);
});
}
};
template <typename Geometry1, typename Geometry2, typename Strategies>
using distance_strategy_t = decltype(
std::declval<Strategies>().distance(std::declval<Geometry1>(), std::declval<Geometry2>()));
template <typename Geometry1, typename Geometry2, typename Strategies>
using creturn_t = typename strategy::distance::services::return_type
<
typename strategy::distance::services::comparable_type
<
distance_strategy_t<Geometry1, Geometry2, Strategies>
>::type,
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type
>::type;
}} // namespace detail::closest_points
}} // namespace boost::geometry
#endif //BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_POINTS_UTILITIES_HPP

View File

@@ -3,11 +3,13 @@
// 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) 2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, 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.
@@ -19,13 +21,18 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
#include <boost/geometry/algorithms/detail/distance/interface.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#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>
#include <boost/geometry/strategies/distance/comparable.hpp>
#include <boost/geometry/strategies/distance/services.hpp>
namespace boost { namespace geometry
@@ -35,47 +42,70 @@ namespace boost { namespace geometry
namespace resolve_strategy
{
template
<
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct comparable_distance
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline
typename comparable_distance_result<Geometry1, Geometry2, Strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
template <typename Geometry1, typename Geometry2>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategies const& strategies)
{
typedef typename strategy::distance::services::comparable_type
return dispatch::distance
<
Strategy
>::type comparable_strategy_type;
Geometry1, Geometry2,
strategies::distance::detail::comparable<Strategies>
>::apply(geometry1,
geometry2,
strategies::distance::detail::comparable<Strategies>(strategies));
}
};
template <typename Strategy>
struct comparable_distance<Strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
using strategies::distance::services::strategy_converter;
using comparable_strategies_type = strategies::distance::detail::comparable
<
decltype(strategy_converter<Strategy>::get(strategy))
>;
return dispatch::distance
<
Geometry1, Geometry2, comparable_strategy_type
Geometry1, Geometry2,
comparable_strategies_type
>::apply(geometry1,
geometry2,
strategy::distance::services::get_comparable
<
Strategy
>::apply(strategy));
comparable_strategies_type(
strategy_converter<Strategy>::get(strategy)));
}
};
template <>
struct comparable_distance<default_strategy, false>
{
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)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategy::distance::services::comparable_type
using comparable_strategy_type = strategies::distance::detail::comparable
<
typename detail::distance::default_strategy
typename strategies::distance::services::default_strategy
<
Geometry1, Geometry2
>::type
>::type comparable_strategy_type;
>;
return dispatch::distance
<
@@ -87,211 +117,110 @@ struct comparable_distance
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
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::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)
typename Geometry1, typename Geometry2,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
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
>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
Strategy const& m_strategy;
visitor(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Geometry1, typename Geometry2>
typename comparable_distance_result
return resolve_strategy::comparable_distance
<
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);
Strategy
>::apply(geometry1, geometry2, strategy);
}
};
} // namespace resolve_variant
template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
struct comparable_distance<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Strategy>
static inline auto apply(DynamicGeometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
using result_t = typename geometry::comparable_distance_result
<
DynamicGeometry1, Geometry2, Strategy
>::type;
result_t result = 0;
traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
{
result = resolve_strategy::comparable_distance
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
struct comparable_distance<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag>
{
template <typename Strategy>
static inline auto apply(Geometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
using result_t = typename geometry::comparable_distance_result
<
Geometry1, DynamicGeometry2, Strategy
>::type;
result_t result = 0;
traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
{
result = resolve_strategy::comparable_distance
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
template <typename DynamicGeometry1, typename DynamicGeometry2>
struct comparable_distance
<
DynamicGeometry1, DynamicGeometry2,
dynamic_geometry_tag, dynamic_geometry_tag
>
{
template <typename Strategy>
static inline auto apply(DynamicGeometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
using result_t = typename geometry::comparable_distance_result
<
DynamicGeometry1, DynamicGeometry2, Strategy
>::type;
result_t result = 0;
traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
{
result = resolve_strategy::comparable_distance
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_dynamic
@@ -314,14 +243,14 @@ struct 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)
inline auto comparable_distance(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return resolve_variant::comparable_distance
return resolve_dynamic::comparable_distance
<
Geometry1,
Geometry2
@@ -347,12 +276,9 @@ comparable_distance(Geometry1 const& geometry1, Geometry2 const& geometry2,
\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)
inline auto comparable_distance(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return geometry::comparable_distance(geometry1, geometry2, default_strategy());
}

View File

@@ -32,6 +32,12 @@ namespace detail { namespace conversion
{
// TODO: Use assignment if possible.
// WARNING: This utility is called in various places for a subset of dimensions.
// In such cases only some of the coordinates should be copied. Alternatively
// there should be a different utility for that called differently than
// convert_xxx, e.g. set_coordinates.
template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount>
struct point_to_point
{

View File

@@ -2,9 +2,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2014, 2018.
// Modifications copyright (c) 2014, 2018 Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2023.
// Modifications copyright (c) 2014-2023 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -14,64 +15,46 @@
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#define BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#ifndef BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_GRAHAM_ANDREW_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_GRAHAM_ANDREW_HPP
#include <cstddef>
#include <algorithm>
#include <vector>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/algorithms/detail/for_each_range.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/strategies/convex_hull.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/strategies/convex_hull/cartesian.hpp>
#include <boost/geometry/strategies/convex_hull/geographic.hpp>
#include <boost/geometry/strategies/convex_hull/spherical.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
namespace strategy { namespace convex_hull
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
namespace detail { namespace convex_hull
{
template
<
typename InputRange,
typename RangeIterator,
typename StrategyLess,
typename StrategyGreater
>
struct get_extremes
// TODO: All of the copies could be avoided if this function stored pointers to points.
// But would it be possible considering that a range can return proxy reference?
template <typename InputProxy, typename Point, typename Less>
inline void get_extremes(InputProxy const& in_proxy,
Point& left, Point& right,
Less const& less)
{
typedef typename point_type<InputRange>::type point_type;
point_type left, right;
bool first;
StrategyLess less;
StrategyGreater greater;
inline get_extremes()
: first(true)
{}
inline void apply(InputRange const& range)
bool first = true;
in_proxy.for_each_range([&](auto const& range)
{
if (boost::size(range) == 0)
if (boost::empty(range))
{
return;
}
@@ -82,19 +65,18 @@ struct get_extremes
// not persistent (in MSVC) this approach is not applicable
// for more ranges together)
RangeIterator left_it = boost::begin(range);
RangeIterator right_it = boost::begin(range);
auto left_it = boost::begin(range);
auto right_it = boost::begin(range);
for (RangeIterator it = boost::begin(range) + 1;
it != boost::end(range);
++it)
auto it = boost::begin(range);
for (++it; it != boost::end(range); ++it)
{
if (less(*it, *left_it))
{
left_it = it;
}
if (greater(*it, *right_it))
if (less(*right_it, *it))
{
right_it = it;
}
@@ -117,48 +99,29 @@ struct get_extremes
left = *left_it;
}
if (greater(*right_it, right))
if (less(right, *right_it))
{
right = *right_it;
}
}
}
};
});
}
template
<
typename InputRange,
typename RangeIterator,
typename Container,
typename SideStrategy
>
struct assign_range
template <typename InputProxy, typename Point, typename Container, typename SideStrategy>
inline void assign_ranges(InputProxy const& in_proxy,
Point const& most_left, Point const& most_right,
Container& lower_points, Container& upper_points,
SideStrategy const& side)
{
Container lower_points, upper_points;
typedef typename point_type<InputRange>::type point_type;
point_type const& most_left;
point_type const& most_right;
inline assign_range(point_type const& left, point_type const& right)
: most_left(left)
, most_right(right)
{}
inline void apply(InputRange const& range)
in_proxy.for_each_range([&](auto const& range)
{
typedef SideStrategy side;
// Put points in one of the two output sequences
for (RangeIterator it = boost::begin(range);
it != boost::end(range);
++it)
for (auto it = boost::begin(range); it != boost::end(range); ++it)
{
// check if it is lying most_left or most_right from the line
int dir = side::apply(most_left, most_right, *it);
int dir = side.apply(most_left, most_right, *it);
switch(dir)
{
case 1 : // left side
@@ -173,41 +136,18 @@ struct assign_range
// -> all never part of hull
}
}
}
};
template <typename Range>
static inline void sort(Range& range)
{
typedef typename boost::range_value<Range>::type point_type;
typedef geometry::less<point_type> comparator;
std::sort(boost::begin(range), boost::end(range), comparator());
});
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
/*!
\brief Graham scan strategy to calculate convex hull
\ingroup strategies
\brief Graham scan algorithm to calculate convex hull
*/
template <typename InputGeometry, typename OutputPoint>
template <typename InputPoint>
class graham_andrew
{
public :
typedef OutputPoint point_type;
typedef InputGeometry geometry_type;
private:
typedef typename cs_tag<point_type>::type cs_tag;
typedef InputPoint point_type;
typedef typename std::vector<point_type> container_type;
typedef typename std::vector<point_type>::const_iterator iterator;
typedef typename std::vector<point_type>::const_reverse_iterator rev_iterator;
class partitions
{
@@ -218,12 +158,23 @@ private:
container_type m_copied_input;
};
public:
typedef partitions state_type;
template <typename InputProxy, typename OutputRing, typename Strategy>
static void apply(InputProxy const& in_proxy, OutputRing & out_ring, Strategy& strategy)
{
partitions state;
apply(in_proxy, state, strategy);
inline void apply(InputGeometry const& geometry, partitions& state) const
result(state,
range::back_inserter(out_ring),
geometry::point_order<OutputRing>::value == clockwise,
geometry::closure<OutputRing>::value != open);
}
private:
template <typename InputProxy, typename Strategy>
static void apply(InputProxy const& in_proxy, partitions& state, Strategy& strategy)
{
// First pass.
// Get min/max (in most cases left / right) points
@@ -237,98 +188,64 @@ public:
// For symmetry and to get often more balanced lower/upper halves
// we keep it.
typedef typename geometry::detail::range_type<InputGeometry>::type range_type;
point_type most_left, most_right;
typedef typename boost::range_iterator
<
range_type const
>::type range_iterator;
geometry::less_exact<point_type, -1, Strategy> less;
detail::get_extremes
<
range_type,
range_iterator,
geometry::less<point_type>,
geometry::greater<point_type>
> extremes;
geometry::detail::for_each_range(geometry, extremes);
detail::convex_hull::get_extremes(in_proxy, most_left, most_right, less);
container_type lower_points, upper_points;
auto const side_strategy = strategy.side();
// Bounding left/right points
// Second pass, now that extremes are found, assign all points
// in either lower, either upper
detail::assign_range
<
range_type,
range_iterator,
container_type,
typename strategy::side::services::default_strategy<cs_tag>::type
> assigner(extremes.left, extremes.right);
geometry::detail::for_each_range(geometry, assigner);
detail::convex_hull::assign_ranges(in_proxy, most_left, most_right,
lower_points, upper_points,
side_strategy);
// Sort both collections, first on x(, then on y)
detail::sort(assigner.lower_points);
detail::sort(assigner.upper_points);
//std::cout << boost::size(assigner.lower_points) << std::endl;
//std::cout << boost::size(assigner.upper_points) << std::endl;
std::sort(boost::begin(lower_points), boost::end(lower_points), less);
std::sort(boost::begin(upper_points), boost::end(upper_points), less);
// And decide which point should be in the final hull
build_half_hull<-1>(assigner.lower_points, state.m_lower_hull,
extremes.left, extremes.right);
build_half_hull<1>(assigner.upper_points, state.m_upper_hull,
extremes.left, extremes.right);
build_half_hull<-1>(lower_points, state.m_lower_hull,
most_left, most_right,
side_strategy);
build_half_hull<1>(upper_points, state.m_upper_hull,
most_left, most_right,
side_strategy);
}
template <typename OutputIterator>
inline void result(partitions const& state,
OutputIterator out,
bool clockwise,
bool closed) const
{
if (clockwise)
{
output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed);
}
else
{
output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed);
}
}
private:
template <int Factor>
template <int Factor, typename SideStrategy>
static inline void build_half_hull(container_type const& input,
container_type& output,
point_type const& left, point_type const& right)
point_type const& left, point_type const& right,
SideStrategy const& side)
{
output.push_back(left);
for(iterator it = input.begin(); it != input.end(); ++it)
for (auto const& i : input)
{
add_to_hull<Factor>(*it, output);
add_to_hull<Factor>(i, output, side);
}
add_to_hull<Factor>(right, output);
add_to_hull<Factor>(right, output, side);
}
template <int Factor>
static inline void add_to_hull(point_type const& p, container_type& output)
template <int Factor, typename SideStrategy>
static inline void add_to_hull(point_type const& p, container_type& output,
SideStrategy const& side)
{
typedef typename strategy::side::services::default_strategy<cs_tag>::type side;
output.push_back(p);
std::size_t output_size = output.size();
while (output_size >= 3)
{
rev_iterator rit = output.rbegin();
auto rit = output.rbegin();
point_type const last = *rit++;
point_type const& last2 = *rit++;
if (Factor * side::apply(*rit, last, last2) <= 0)
if (Factor * side.apply(*rit, last, last2) <= 0)
{
// Remove last two points from stack, and add last again
// This is much faster then erasing the one but last.
@@ -346,8 +263,23 @@ private:
template <typename OutputIterator>
static inline void output_ranges(container_type const& first, container_type const& second,
OutputIterator out, bool closed)
static void result(partitions const& state, OutputIterator out, bool clockwise, bool closed)
{
if (clockwise)
{
output_ranges(state.m_upper_hull, state.m_lower_hull, out, closed);
}
else
{
output_ranges(state.m_lower_hull, state.m_upper_hull, out, closed);
}
}
template <typename OutputIterator>
static inline void output_ranges(container_type const& first,
container_type const& second,
OutputIterator out,
bool closed)
{
std::copy(boost::begin(first), boost::end(first), out);
@@ -369,18 +301,10 @@ private:
}
};
}} // namespace strategy::convex_hull
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
template <typename InputGeometry, typename OutputPoint>
struct strategy_convex_hull<InputGeometry, OutputPoint, cartesian_tag>
{
typedef strategy::convex_hull::graham_andrew<InputGeometry, OutputPoint> type;
};
#endif
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_STRATEGIES_AGNOSTIC_CONVEX_GRAHAM_ANDREW_HPP
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_GRAHAM_ANDREW_HPP

View File

@@ -0,0 +1,617 @@
// 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) 2023 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021 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_CONVEX_HULL_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP
#include <array>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/convex_hull/graham_andrew.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/algorithms/detail/for_each_range.hpp>
#include <boost/geometry/algorithms/detail/select_geometry_type.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/geometry_types.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/strategies/convex_hull/cartesian.hpp>
#include <boost/geometry/strategies/convex_hull/geographic.hpp>
#include <boost/geometry/strategies/convex_hull/spherical.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/util/sequence.hpp>
#include <boost/geometry/util/type_traits.hpp>
namespace boost { namespace geometry
{
// TODO: This file is named interface.hpp but the code below is not the interface.
// It's the implementation of the algorithm.
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace convex_hull
{
// Abstraction representing ranges/rings of a geometry
template <typename Geometry>
struct input_geometry_proxy
{
input_geometry_proxy(Geometry const& geometry)
: m_geometry(geometry)
{}
template <typename UnaryFunction>
inline void for_each_range(UnaryFunction fun) const
{
geometry::detail::for_each_range(m_geometry, fun);
}
Geometry const& m_geometry;
};
// Abstraction representing ranges/rings of subgeometries of geometry collection
// with boxes converted to rings
template <typename Geometry, typename BoxRings>
struct input_geometry_collection_proxy
{
input_geometry_collection_proxy(Geometry const& geometry, BoxRings const& box_rings)
: m_geometry(geometry)
, m_box_rings(box_rings)
{}
template <typename UnaryFunction>
inline void for_each_range(UnaryFunction fun) const
{
detail::visit_breadth_first([&](auto const& g)
{
input_geometry_collection_proxy::call_for_non_boxes(g, fun);
return true;
}, m_geometry);
for (auto const& r : m_box_rings)
{
geometry::detail::for_each_range(r, fun);
}
}
private:
template <typename G, typename F, std::enable_if_t<! util::is_box<G>::value, int> = 0>
static inline void call_for_non_boxes(G const& g, F & f)
{
geometry::detail::for_each_range(g, f);
}
template <typename G, typename F, std::enable_if_t<util::is_box<G>::value, int> = 0>
static inline void call_for_non_boxes(G const&, F &)
{}
Geometry const& m_geometry;
BoxRings const& m_box_rings;
};
// TODO: Or just implement point_type<> for GeometryCollection
// and enforce the same point_type used in the whole sequence in check().
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct default_strategy
{
using type = typename strategies::convex_hull::services::default_strategy
<
Geometry
>::type;
};
template <typename Geometry>
struct default_strategy<Geometry, geometry_collection_tag>
: default_strategy<typename detail::first_geometry_type<Geometry>::type>
{};
// Utilities for output GC and DG
template <typename G1, typename G2>
struct output_polygonal_less
{
template <typename G>
using priority = std::integral_constant
<
int,
(util::is_ring<G>::value ? 0 :
util::is_polygon<G>::value ? 1 :
util::is_multi_polygon<G>::value ? 2 : 3)
>;
static const bool value = priority<G1>::value < priority<G2>::value;
};
template <typename G1, typename G2>
struct output_linear_less
{
template <typename G>
using priority = std::integral_constant
<
int,
(util::is_segment<G>::value ? 0 :
util::is_linestring<G>::value ? 1 :
util::is_multi_linestring<G>::value ? 2 : 3)
>;
static const bool value = priority<G1>::value < priority<G2>::value;
};
template <typename G1, typename G2>
struct output_pointlike_less
{
template <typename G>
using priority = std::integral_constant
<
int,
(util::is_point<G>::value ? 0 :
util::is_multi_point<G>::value ? 1 : 2)
>;
static const bool value = priority<G1>::value < priority<G2>::value;
};
}} // 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
{
template <typename OutputGeometry, typename Strategy>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategy const& strategy)
{
detail::convex_hull::input_geometry_proxy<Geometry> in_proxy(geometry);
detail::convex_hull::graham_andrew
<
typename point_type<Geometry>::type
>::apply(in_proxy, out, strategy);
}
};
// A hull for boxes is trivial. Any strategy is (currently) skipped.
// TODO: This is not correct in spherical and geographic CS.
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;
std::array<typename point_type<OutputGeometry>::type, 4> arr;
// TODO: This assigns only 2d cooridnates!
// And it is also used in box_view<>!
geometry::detail::assign_box_corners_oriented<Reverse>(box, arr);
std::move(arr.begin(), arr.end(), range::back_inserter(out));
if (BOOST_GEOMETRY_CONDITION(Close))
{
range::push_back(out, range::front(out));
}
}
};
template <typename GeometryCollection>
struct convex_hull<GeometryCollection, geometry_collection_tag>
{
template <typename OutputGeometry, typename Strategy>
static inline void apply(GeometryCollection const& geometry,
OutputGeometry& out,
Strategy const& strategy)
{
// Assuming that single point_type is used by the GeometryCollection
using subgeometry_type = typename detail::first_geometry_type<GeometryCollection>::type;
using point_type = typename geometry::point_type<subgeometry_type>::type;
using ring_type = model::ring<point_type, true, false>;
// Calculate box rings once
std::vector<ring_type> box_rings;
detail::visit_breadth_first([&](auto const& g)
{
convex_hull::add_ring_for_box(box_rings, g, strategy);
return true;
}, geometry);
detail::convex_hull::input_geometry_collection_proxy
<
GeometryCollection, std::vector<ring_type>
> in_proxy(geometry, box_rings);
detail::convex_hull::graham_andrew
<
point_type
>::apply(in_proxy, out, strategy);
}
private:
template
<
typename Ring, typename SubGeometry, typename Strategy,
std::enable_if_t<util::is_box<SubGeometry>::value, int> = 0
>
static inline void add_ring_for_box(std::vector<Ring> & rings, SubGeometry const& box,
Strategy const& strategy)
{
Ring ring;
convex_hull<SubGeometry>::apply(box, ring, strategy);
rings.push_back(std::move(ring));
}
template
<
typename Ring, typename SubGeometry, typename Strategy,
std::enable_if_t<! util::is_box<SubGeometry>::value, int> = 0
>
static inline void add_ring_for_box(std::vector<Ring> & , SubGeometry const& ,
Strategy const& )
{}
};
template <typename OutputGeometry, typename Tag = typename tag<OutputGeometry>::type>
struct convex_hull_out
{
BOOST_GEOMETRY_STATIC_ASSERT_FALSE("This OutputGeometry is not supported.", OutputGeometry, Tag);
};
template <typename OutputGeometry>
struct convex_hull_out<OutputGeometry, ring_tag>
{
template <typename Geometry, typename Strategies>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategies const& strategies)
{
dispatch::convex_hull<Geometry>::apply(geometry, out, strategies);
}
};
template <typename OutputGeometry>
struct convex_hull_out<OutputGeometry, polygon_tag>
{
template <typename Geometry, typename Strategies>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategies const& strategies)
{
auto&& ring = exterior_ring(out);
dispatch::convex_hull<Geometry>::apply(geometry, ring, strategies);
}
};
template <typename OutputGeometry>
struct convex_hull_out<OutputGeometry, multi_polygon_tag>
{
template <typename Geometry, typename Strategies>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategies const& strategies)
{
typename boost::range_value<OutputGeometry>::type polygon;
auto&& ring = exterior_ring(polygon);
dispatch::convex_hull<Geometry>::apply(geometry, ring, strategies);
// Empty input is checked so the output shouldn't be empty
range::push_back(out, std::move(polygon));
}
};
template <typename OutputGeometry>
struct convex_hull_out<OutputGeometry, geometry_collection_tag>
{
using polygonal_t = typename util::sequence_min_element
<
typename traits::geometry_types<OutputGeometry>::type,
detail::convex_hull::output_polygonal_less
>::type;
using linear_t = typename util::sequence_min_element
<
typename traits::geometry_types<OutputGeometry>::type,
detail::convex_hull::output_linear_less
>::type;
using pointlike_t = typename util::sequence_min_element
<
typename traits::geometry_types<OutputGeometry>::type,
detail::convex_hull::output_pointlike_less
>::type;
// select_element may define different kind of geometry than the one that is desired
BOOST_GEOMETRY_STATIC_ASSERT(util::is_polygonal<polygonal_t>::value,
"It must be possible to store polygonal geometry in OutputGeometry.", polygonal_t);
BOOST_GEOMETRY_STATIC_ASSERT(util::is_linear<linear_t>::value,
"It must be possible to store linear geometry in OutputGeometry.", linear_t);
BOOST_GEOMETRY_STATIC_ASSERT(util::is_pointlike<pointlike_t>::value,
"It must be possible to store pointlike geometry in OutputGeometry.", pointlike_t);
template <typename Geometry, typename Strategies>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategies const& strategies)
{
polygonal_t polygonal;
convex_hull_out<polygonal_t>::apply(geometry, polygonal, strategies);
// Empty input is checked so the output shouldn't be empty
auto&& out_ring = ring(polygonal);
if (boost::size(out_ring) == detail::minimum_ring_size<polygonal_t>::value)
{
using detail::equals::equals_point_point;
if (equals_point_point(range::front(out_ring), range::at(out_ring, 1), strategies))
{
pointlike_t pointlike;
move_to_pointlike(out_ring, pointlike);
move_to_out(pointlike, out);
return;
}
if (equals_point_point(range::front(out_ring), range::at(out_ring, 2), strategies))
{
linear_t linear;
move_to_linear(out_ring, linear);
move_to_out(linear, out);
return;
}
}
move_to_out(polygonal, out);
}
private:
template <typename Polygonal, util::enable_if_ring_t<Polygonal, int> = 0>
static decltype(auto) ring(Polygonal const& polygonal)
{
return polygonal;
}
template <typename Polygonal, util::enable_if_polygon_t<Polygonal, int> = 0>
static decltype(auto) ring(Polygonal const& polygonal)
{
return exterior_ring(polygonal);
}
template <typename Polygonal, util::enable_if_multi_polygon_t<Polygonal, int> = 0>
static decltype(auto) ring(Polygonal const& polygonal)
{
return exterior_ring(range::front(polygonal));
}
template <typename Range, typename Linear, util::enable_if_segment_t<Linear, int> = 0>
static void move_to_linear(Range & out_range, Linear & seg)
{
detail::assign_point_to_index<0>(range::front(out_range), seg);
detail::assign_point_to_index<1>(range::at(out_range, 1), seg);
}
template <typename Range, typename Linear, util::enable_if_linestring_t<Linear, int> = 0>
static void move_to_linear(Range & out_range, Linear & ls)
{
std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls));
}
template <typename Range, typename Linear, util::enable_if_multi_linestring_t<Linear, int> = 0>
static void move_to_linear(Range & out_range, Linear & mls)
{
typename boost::range_value<Linear>::type ls;
std::move(boost::begin(out_range), boost::begin(out_range) + 2, range::back_inserter(ls));
range::push_back(mls, std::move(ls));
}
template <typename Range, typename PointLike, util::enable_if_point_t<PointLike, int> = 0>
static void move_to_pointlike(Range & out_range, PointLike & pt)
{
pt = range::front(out_range);
}
template <typename Range, typename PointLike, util::enable_if_multi_point_t<PointLike, int> = 0>
static void move_to_pointlike(Range & out_range, PointLike & mpt)
{
range::push_back(mpt, std::move(range::front(out_range)));
}
template
<
typename Geometry, typename OutputGeometry_,
util::enable_if_geometry_collection_t<OutputGeometry_, int> = 0
>
static void move_to_out(Geometry & g, OutputGeometry_ & out)
{
range::emplace_back(out, std::move(g));
}
template
<
typename Geometry, typename OutputGeometry_,
util::enable_if_dynamic_geometry_t<OutputGeometry_, int> = 0
>
static void move_to_out(Geometry & g, OutputGeometry_ & out)
{
out = std::move(g);
}
};
template <typename OutputGeometry>
struct convex_hull_out<OutputGeometry, dynamic_geometry_tag>
: convex_hull_out<OutputGeometry, geometry_collection_tag>
{};
// For backward compatibility
template <typename OutputGeometry>
struct convex_hull_out<OutputGeometry, linestring_tag>
: convex_hull_out<OutputGeometry, ring_tag>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy {
template <typename Strategies>
struct convex_hull
{
template <typename Geometry, typename OutputGeometry>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategies const& strategies)
{
dispatch::convex_hull_out<OutputGeometry>::apply(geometry, out, strategies);
}
};
template <>
struct convex_hull<default_strategy>
{
template <typename Geometry, typename OutputGeometry>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
default_strategy const&)
{
using strategy_type = typename detail::convex_hull::default_strategy
<
Geometry
>::type;
dispatch::convex_hull_out<OutputGeometry>::apply(geometry, out, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic {
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
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<Strategy>::apply(geometry, out, strategy);
}
};
template <typename Geometry>
struct convex_hull<Geometry, dynamic_geometry_tag>
{
template <typename OutputGeometry, typename Strategy>
static inline void apply(Geometry const& geometry,
OutputGeometry& out,
Strategy const& strategy)
{
traits::visit<Geometry>::apply([&](auto const& g)
{
convex_hull<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy);
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
\brief \brief_calc{convex hull} \brief_strategy
\ingroup convex_hull
\details \details_calc{convex_hull,convex hull} \brief_strategy.
\tparam Geometry the input geometry type
\tparam OutputGeometry the output geometry type
\tparam Strategy the strategy type
\param geometry \param_geometry, input geometry
\param out \param_geometry \param_set{convex hull}
\param strategy \param_strategy{area}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/convex_hull.qbk]}
*/
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_dynamic::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());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_INTERFACE_HPP

View File

@@ -5,10 +5,10 @@
// Copyright (c) 2009-2014 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.
// 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.
@@ -22,15 +22,14 @@
#include <cstddef>
#include <boost/range.hpp>
#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
{
@@ -66,10 +65,8 @@ struct polygon_count
{
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)
auto const& rings = interior_rings(poly);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
n += RangeCount::apply(*it);
}
@@ -83,13 +80,10 @@ template <typename SingleCount>
struct multi_count
{
template <typename MultiGeometry>
static inline std::size_t apply(MultiGeometry const& geometry)
static inline std::size_t apply(MultiGeometry const& multi)
{
std::size_t n = 0;
for (typename boost::range_iterator<MultiGeometry const>::type
it = boost::begin(geometry);
it != boost::end(geometry);
++it)
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
n += SingleCount::apply(*it);
}

View File

@@ -1,40 +0,0 @@
// 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

View File

@@ -4,9 +4,10 @@
// 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.
// This file was modified by Oracle on 2013-2022.
// Modifications copyright (c) 2013-2022 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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
@@ -23,6 +24,9 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/within/implementation.hpp>
#include <boost/geometry/strategies/relate/cartesian.hpp>
#include <boost/geometry/strategies/relate/geographic.hpp>
#include <boost/geometry/strategies/relate/spherical.hpp>
namespace boost { namespace geometry
@@ -34,7 +38,8 @@ 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)
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return detail::within::covered_by_point_geometry(geometry1, geometry2, strategy);
}
@@ -43,13 +48,32 @@ struct use_point_in_geometry
struct use_relate
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef typename detail::de9im::static_mask_covered_by_type
return detail::relate::relate_impl
<
Geometry1, Geometry2
>::type covered_by_mask;
return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy);
detail::de9im::static_mask_covered_by_type,
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
};
struct geometry_covered_by_box
{
template <typename Geometry, typename Box, typename Strategy>
static inline bool apply(Geometry const& geometry, Box const& box, Strategy const& strategy)
{
using point_type = typename point_type<Geometry>::type;
using mutable_point_type = typename helper_geometry<point_type>::type;
using box_type = model::box<mutable_point_type>;
// TODO: this is not optimal since the process should be able to terminate if a point is found
// outside of the box without computing the whole envelope
box_type box_areal;
geometry::envelope(geometry, box_areal, strategy);
return strategy.covered_by(box_areal, box).apply(box_areal, box);
}
};
@@ -60,30 +84,6 @@ struct use_relate
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>
@@ -271,6 +271,76 @@ struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon
: public detail::covered_by::use_relate
{};
// B/A
template <typename Box, typename Polygon>
struct covered_by<Box, Polygon, box_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Box, typename Polygon>
struct covered_by<Box, Polygon, box_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Box, typename Polygon>
struct covered_by<Box, Polygon, box_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
// Geometry/Box
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)
{
return strategy.covered_by(point, box).apply(point, box);
}
};
template <typename MultiPoint, typename Box>
struct covered_by<MultiPoint, Box, multi_point_tag, box_tag>
: public detail::covered_by::geometry_covered_by_box
{};
template <typename Linestring, typename Box>
struct covered_by<Linestring, Box, linestring_tag, box_tag>
: public detail::covered_by::geometry_covered_by_box
{};
template <typename MultiLinestring, typename Box>
struct covered_by<MultiLinestring, Box, multi_linestring_tag, box_tag>
: public detail::covered_by::geometry_covered_by_box
{};
template <typename Ring, typename Box>
struct covered_by<Ring, Box, ring_tag, box_tag>
: public detail::covered_by::geometry_covered_by_box
{};
template <typename Polygon, typename Box>
struct covered_by<Polygon, Box, polygon_tag, box_tag>
: public detail::covered_by::geometry_covered_by_box
{};
template <typename MultiPolygon, typename Box>
struct covered_by<MultiPolygon, Box, multi_polygon_tag, box_tag>
: public detail::covered_by::geometry_covered_by_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>();
return strategy.covered_by(box1, box2).apply(box1, box2);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH

View File

@@ -0,0 +1,46 @@
// Boost.Geometry
// Copyright (c) 2022 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_COVERED_BY_IMPLEMENTATION_GC_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_GC_HPP
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/relate/implementation_gc.hpp>
namespace boost { namespace geometry {
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch {
template <typename Geometry1, typename Geometry2>
struct covered_by<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag>
: detail::covered_by::use_relate
{};
template <typename Geometry1, typename Geometry2, typename Tag1>
struct covered_by<Geometry1, Geometry2, Tag1, geometry_collection_tag>
: detail::covered_by::use_relate
{};
template <typename Geometry1, typename Geometry2, typename Tag2>
struct covered_by<Geometry1, Geometry2, geometry_collection_tag, Tag2>
: detail::covered_by::use_relate
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_GC_HPP

View File

@@ -4,9 +4,8 @@
// 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.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021 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
@@ -20,16 +19,12 @@
#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>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/relate/services.hpp>
namespace boost { namespace geometry
@@ -56,9 +51,14 @@ struct covered_by
namespace resolve_strategy {
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct covered_by
{
template <typename Geometry1, typename Geometry2, typename Strategy>
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
@@ -68,32 +68,63 @@ struct covered_by
concepts::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
geometry2,
strategy);
return dispatch::covered_by
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
};
template <typename Strategy>
struct covered_by<Strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
using strategies::relate::services::strategy_converter;
return covered_by
<
decltype(strategy_converter<Strategy>::get(strategy))
>::apply(geometry1, geometry2,
strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct covered_by<default_strategy, false>
{
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
typedef typename strategies::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return covered_by::apply(geometry1, geometry2, strategy_type());
return covered_by
<
strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry1, typename Geometry2>
template
<
typename Geometry1, typename Geometry2,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct covered_by
{
template <typename Strategy>
@@ -102,106 +133,73 @@ struct covered_by
Strategy const& strategy)
{
return resolve_strategy::covered_by
::apply(geometry1, geometry2, strategy);
<
Strategy
>::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 Geometry1, typename Geometry2, typename Tag2>
struct covered_by<Geometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
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
bool result = false;
traits::visit<Geometry1>::apply([&](auto const& g1)
{
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);
result = resolve_strategy::covered_by
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry1, typename Geometry2, typename Tag1>
struct covered_by<Geometry1, Geometry2, Tag1, dynamic_geometry_tag>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
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
bool result = false;
traits::visit<Geometry2>::apply([&](auto const& g2)
{
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);
result = resolve_strategy::covered_by
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
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 Geometry1, typename Geometry2>
struct covered_by<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag>
{
template <typename Strategy>
struct visitor: boost::static_visitor<bool>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
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
bool result = false;
traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2)
{
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);
result = resolve_strategy::covered_by
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
@@ -217,13 +215,19 @@ struct covered_by<
\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());
return resolve_dynamic::covered_by
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, default_strategy());
}
/*!
@@ -246,8 +250,10 @@ 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);
return resolve_dynamic::covered_by
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry

View File

@@ -1,9 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2015-2020 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// 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
@@ -12,17 +12,20 @@
// 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_DIRECITON_CODE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
#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>
#include <boost/mpl/assert.hpp>
namespace boost { namespace geometry
{
@@ -32,108 +35,111 @@ namespace boost { namespace geometry
namespace detail
{
// TODO: remove
template <std::size_t Index, typename Point1, typename Point2>
inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
{
return
math::equals(geometry::get<Index>(point1), geometry::get<Index>(point2))
?
0
:
(geometry::get<Index>(point1) > geometry::get<Index>(point2) ? 1 : -1);
}
template <typename Point, typename CSTag = typename cs_tag<Point>::type>
template <typename CSTag>
struct direction_code_impl
{
BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
"Not implemented for this coordinate system.",
CSTag);
};
template <typename Point>
struct direction_code_impl<Point, cartesian_tag>
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& p)
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
Point2 const& point)
{
typedef typename geometry::select_coordinate_type
using calc_t = typename geometry::select_coordinate_type
<
Point1, Point2
>::type calc_t;
PointSegmentA, PointSegmentB, Point2
>::type;
if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a))
&& math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a)))
|| (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p))
&& math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) )
using line_type = model::infinite_line<calc_t>;
// 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 x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a);
calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a);
calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p);
calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p);
calc_t ax = (std::min)(math::abs(x1), math::abs(x2));
calc_t ay = (std::min)(math::abs(y1), math::abs(y2));
int s1 = 0, s2 = 0;
if (ax >= ay)
{
s1 = x1 > 0 ? 1 : -1;
s2 = x2 > 0 ? 1 : -1;
}
else
{
s1 = y1 > 0 ? 1 : -1;
s2 = y2 > 0 ? 1 : -1;
}
return s1 == s2 ? -1 : 1;
calc_t const sv = arithmetic::side_value(line, point);
static calc_t const zero = 0;
return sv == zero ? 0 : sv > zero ? 1 : -1;
}
};
template <typename Point>
struct direction_code_impl<Point, spherical_equatorial_tag>
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,
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
Point2 const& p)
{
typedef typename coordinate_type<Point1>::type coord1_t;
typedef typename coordinate_type<Point2>::type coord2_t;
typedef typename coordinate_system<Point1>::type::units units_t;
typedef typename coordinate_system<Point2>::type::units units2_t;
BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
(units_t, units2_t));
{
using units_sa_t = typename cs_angular_units<PointSegmentA>::type;
using units_sb_t = typename cs_angular_units<PointSegmentB>::type;
using units_p_t = typename cs_angular_units<Point2>::type;
BOOST_GEOMETRY_STATIC_ASSERT(
(std::is_same<units_sa_t, units_sb_t>::value),
"Not implemented for different units.",
units_sa_t, units_sb_t);
BOOST_GEOMETRY_STATIC_ASSERT(
(std::is_same<units_sa_t, units_p_t>::value),
"Not implemented for different units.",
units_sa_t, units_p_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();
using coor_sa_t = typename coordinate_type<PointSegmentA>::type;
using coor_sb_t = typename coordinate_type<PointSegmentB>::type;
using coor_p_t = typename coordinate_type<Point2>::type;
// Declare unit type (equal for all types) and calc type (coerced to most precise)
using units_t = typename cs_angular_units<Point2>::type;
using calc_t = typename geometry::select_coordinate_type
<
PointSegmentA, PointSegmentB, Point2
>::type;
using constants_sa_t = math::detail::constants_on_spheroid<coor_sa_t, units_t>;
using constants_sb_t = math::detail::constants_on_spheroid<coor_sb_t, units_t>;
using constants_p_t = math::detail::constants_on_spheroid<coor_p_t, units_t>;
static coor_sa_t const pi_half_sa = constants_sa_t::max_latitude();
static coor_sb_t const pi_half_sb = constants_sb_t::max_latitude();
static coor_p_t const pi_half_p = constants_p_t::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);
coor_sa_t const a0 = geometry::get<0>(segment_a);
coor_sa_t const a1 = geometry::get<1>(segment_a);
coor_sb_t const b0 = geometry::get<0>(segment_b);
coor_sb_t const b1 = geometry::get<1>(segment_b);
coor_p_t const p0 = geometry::get<0>(p);
coor_p_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));
bool const is_a_pole = math::equals(pi_half_sa, math::abs(a1));
bool const is_b_pole = math::equals(pi_half_sb, math::abs(b1));
bool const is_p_pole = math::equals(pi_half_p, 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))) )
@@ -151,12 +157,12 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
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));
calc_t const 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 const my = (std::min)(math::abs(dlat1),
math::abs(dlat2));
int s1 = 0, s2 = 0;
if (mx >= my)
@@ -176,7 +182,7 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
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;
using constants = math::detail::constants_on_spheroid<T, Units>;
static T const pi = constants::half_period();
static T const c0 = 0;
@@ -196,41 +202,66 @@ struct direction_code_impl<Point, spherical_equatorial_tag>
}
};
template <typename Point>
struct direction_code_impl<Point, spherical_polar_tag>
template <>
struct direction_code_impl<spherical_polar_tag>
{
template <typename Point1, typename Point2>
static inline int apply(Point1 segment_a, Point1 segment_b,
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b,
Point2 p)
{
typedef math::detail::constants_on_spheroid
using constants_sa_t = math::detail::constants_on_spheroid
<
typename coordinate_type<Point1>::type,
typename coordinate_system<Point1>::type::units
> constants1;
typedef math::detail::constants_on_spheroid
typename coordinate_type<PointSegmentA>::type,
typename cs_angular_units<PointSegmentA>::type
>;
using constants_p_t = math::detail::constants_on_spheroid
<
typename coordinate_type<Point2>::type,
typename coordinate_system<Point2>::type::units
> constants2;
typename cs_angular_units<Point2>::type
>;
geometry::set<1>(segment_a,
constants1::max_latitude() - geometry::get<1>(segment_a));
constants_sa_t::max_latitude() - geometry::get<1>(segment_a));
geometry::set<1>(segment_b,
constants1::max_latitude() - geometry::get<1>(segment_b));
constants_sa_t::max_latitude() - geometry::get<1>(segment_b));
geometry::set<1>(p,
constants2::max_latitude() - geometry::get<1>(p));
constants_p_t::max_latitude() - geometry::get<1>(p));
return direction_code_impl
<
Point, spherical_equatorial_tag
spherical_equatorial_tag
>::apply(segment_a, segment_b, p);
}
};
template <typename Point>
struct direction_code_impl<Point, geographic_tag>
: direction_code_impl<Point, spherical_equatorial_tag>
// if spherical_tag is passed then pick cs_tag based on PointSegmentA type
// with spherical_equatorial_tag as the default
template <>
struct direction_code_impl<spherical_tag>
{
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b,
Point2 p)
{
return direction_code_impl
<
std::conditional_t
<
std::is_same
<
typename geometry::cs_tag<PointSegmentA>::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)
@@ -238,11 +269,13 @@ struct direction_code_impl<Point, geographic_tag>
// 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 Point1, typename Point2>
inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
// In some cases the "segment" consists of different source points, and therefore
// their types might differ.
template <typename CSTag, typename PointSegmentA, typename PointSegmentB, typename Point2>
inline int direction_code(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
Point2 const& p)
{
return direction_code_impl<Point1>::apply(segment_a, segment_b, p);
return direction_code_impl<CSTag>::apply(segment_a, segment_b, p);
}
@@ -252,4 +285,4 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2019.
// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2022.
// Modifications copyright (c) 2013-2022, 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
@@ -23,14 +23,16 @@
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.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/iterators/segment_iterator.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
#include <boost/geometry/algorithms/for_each.hpp>
namespace boost { namespace geometry
@@ -46,51 +48,25 @@ inline bool point_on_border_covered_by(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
typename geometry::point_type<Geometry1>::type pt;
using point_type = typename geometry::point_type<Geometry1>::type;
typename helper_geometry<point_type>::type pt;
return geometry::point_on_border(pt, geometry1)
&& geometry::covered_by(pt, geometry2, strategy);
}
/*!
\tparam Strategy point_in_geometry strategy
*/
template<typename Geometry, typename Strategy>
struct check_each_ring_for_within
{
bool not_disjoint;
Geometry const& m_geometry;
Strategy const& m_strategy;
inline check_each_ring_for_within(Geometry const& g,
Strategy const& strategy)
: not_disjoint(false)
, m_geometry(g)
, m_strategy(strategy)
{}
template <typename Range>
inline void apply(Range const& range)
{
not_disjoint = not_disjoint
|| point_on_border_covered_by(range, m_geometry, m_strategy);
}
};
/*!
\tparam Strategy point_in_geometry strategy
*/
template <typename FirstGeometry, typename SecondGeometry, typename Strategy>
inline bool rings_containing(FirstGeometry const& geometry1,
SecondGeometry const& geometry2,
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool rings_containing(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
check_each_ring_for_within
<
FirstGeometry, Strategy
> checker(geometry1, strategy);
geometry::detail::for_each_range(geometry2, checker);
return checker.not_disjoint;
return geometry::detail::any_range_of(geometry2, [&](auto const& range)
{
return point_on_border_covered_by(range, geometry1, strategy);
});
}
@@ -117,10 +93,8 @@ struct areal_areal
// 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.template get_point_in_geometry_strategy<Geometry2, Geometry1>())
|| rings_containing(geometry2, geometry1,
strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>()) )
if ( rings_containing(geometry1, geometry2, strategy)
|| rings_containing(geometry2, geometry1, strategy) )
{
return false;
}
@@ -141,10 +115,10 @@ struct areal_box
Box const& box,
Strategy const& strategy)
{
if ( ! for_each_segment(geometry::segments_begin(areal),
geometry::segments_end(areal),
box,
strategy.get_disjoint_segment_box_strategy()) )
if (! geometry::all_segments_of(areal, [&](auto const& s)
{
return disjoint_segment_box::apply(s, box, strategy);
}) )
{
return false;
}
@@ -152,31 +126,13 @@ struct areal_box
// 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>()) )
if ( point_on_border_covered_by(box, areal, strategy) )
{
return false;
}
return true;
}
private:
template <typename SegIter, typename Strategy>
static inline bool for_each_segment(SegIter first,
SegIter last,
Box const& box,
Strategy const& strategy)
{
for ( ; first != last ; ++first)
{
if (! disjoint_segment_box::apply(*first, box, strategy))
{
return false;
}
}
return true;
}
};

View File

@@ -5,9 +5,8 @@
// 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.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021, 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
@@ -25,9 +24,7 @@
#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>
#include <boost/geometry/strategies/detail.hpp>
namespace boost { namespace geometry
{
@@ -43,8 +40,23 @@ namespace detail { namespace 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&)
template
<
typename Box1, typename Box2, typename Strategy,
std::enable_if_t<strategies::detail::is_umbrella_strategy<Strategy>::value, int> = 0
>
inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
typedef decltype(strategy.disjoint(box1, box2)) strategy_type;
return strategy_type::apply(box1, box2);
}
template
<
typename Box1, typename Box2, typename Strategy,
std::enable_if_t<! strategies::detail::is_umbrella_strategy<Strategy>::value, int> = 0
>
inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2, Strategy const& )
{
return Strategy::apply(box1, box2);
}
@@ -63,9 +75,10 @@ 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&)
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
return Strategy::apply(box1, box2);
typedef decltype(strategy.disjoint(box1, box2)) strategy_type;
return strategy_type::apply(box1, box2);
}
};

View File

@@ -5,8 +5,8 @@
// 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.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021, 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
@@ -33,5 +33,9 @@
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
#include <boost/geometry/strategies/relate/cartesian.hpp>
#include <boost/geometry/strategies/relate/geographic.hpp>
#include <boost/geometry/strategies/relate/spherical.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP

View File

@@ -5,8 +5,8 @@
// 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.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021, 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
@@ -23,16 +23,16 @@
#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/detail/visit.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/relate/services.hpp>
namespace boost { namespace geometry
@@ -41,9 +41,14 @@ namespace boost { namespace geometry
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct disjoint
{
template <typename Geometry1, typename Geometry2, typename Strategy>
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
@@ -53,13 +58,35 @@ struct disjoint
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
};
template <typename Strategy>
struct disjoint<Strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
using strategies::relate::services::strategy_converter;
return dispatch::disjoint
<
Geometry1, Geometry2
>::apply(geometry1, geometry2,
strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct disjoint<default_strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategy::disjoint::services::default_strategy
typedef typename strategies::relate::services::default_strategy
<
Geometry1, Geometry2
>::type strategy_type;
@@ -74,13 +101,21 @@ struct disjoint
} // namespace resolve_strategy
namespace resolve_variant {
namespace resolve_dynamic {
template <typename Geometry1, typename Geometry2>
template
<
typename Geometry1, typename Geometry2,
bool IsDynamic = util::is_dynamic_geometry<Geometry1>::value
|| util::is_dynamic_geometry<Geometry2>::value,
bool IsCollection = util::is_geometry_collection<Geometry1>::value
|| util::is_geometry_collection<Geometry2>::value
>
struct disjoint
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check_concepts_and_equal_dimensions
<
@@ -88,108 +123,60 @@ struct disjoint
Geometry2 const
>();
return resolve_strategy::disjoint::apply(geometry1, geometry2, strategy);
return resolve_strategy::disjoint
<
Strategy
>::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 Geometry1, typename Geometry2>
struct disjoint<Geometry1, Geometry2, true, false>
{
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,
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
bool result = true;
detail::visit([&](auto const& g1, auto const& g2)
{
result = disjoint
<
util::remove_cref_t<decltype(g1)>, util::remove_cref_t<decltype(g2)>
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct disjoint<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
// TODO: The complexity is quadratic for two GCs
// Decrease e.g. with spatial index
template <typename Geometry1, typename Geometry2, bool IsDynamic>
struct disjoint<Geometry1, Geometry2, IsDynamic, true>
{
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,
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
bool result = true;
detail::visit_breadth_first([&](auto const& g1)
{
detail::visit_breadth_first([&](auto const& g2)
{
result = disjoint
<
util::remove_cref_t<decltype(g1)>, util::remove_cref_t<decltype(g2)>
>::apply(g1, g2, strategy);
// If any of the combination intersects then the final result is not disjoint
return result;
}, geometry2);
return result;
}, geometry1);
return result;
}
};
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
} // namespace resolve_dynamic
/*!
@@ -211,7 +198,7 @@ inline bool disjoint(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_variant::disjoint
return resolve_dynamic::disjoint
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
@@ -228,12 +215,17 @@ inline bool disjoint(Geometry1 const& geometry1,
\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
return resolve_dynamic::disjoint
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, default_strategy());

View File

@@ -5,11 +5,12 @@
// 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.
// This file was modified by Oracle on 2013-2022.
// Modifications copyright (c) 2013-2022, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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.
@@ -23,7 +24,9 @@
#include <iterator>
#include <boost/range.hpp>
#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>
@@ -34,11 +37,10 @@
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.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>
@@ -49,6 +51,7 @@
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
namespace boost { namespace geometry
{
@@ -68,11 +71,11 @@ struct disjoint_no_intersections_policy
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;
using point_type = typename point_type<Geometry1>::type;
typename helper_geometry<point_type>::type p;
geometry::point_on_border(p, g1);
return !geometry::covered_by(p, g2, strategy);
return ! geometry::covered_by(p, g2, strategy);
}
};
@@ -86,12 +89,11 @@ struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag>
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 )
for (auto 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) )
if (! disjoint_no_intersections_policy<value_type const, Geometry2>
::apply(*it, g2, strategy))
{
return false;
}
@@ -118,9 +120,7 @@ struct disjoint_linear_areal
return false;
}
return NoIntersectionsPolicy
::apply(g1, g2,
strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>());
return NoIntersectionsPolicy::apply(g1, g2, strategy);
}
};
@@ -141,31 +141,25 @@ struct disjoint_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;
using ring_type = typename boost::range_value<InteriorRings>::type;
typedef unary_disjoint_geometry_to_query_geometry
using unary_predicate_type = 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));
disjoint_range_segment_or_box<ring_type, Segment>
>;
return std::all_of(boost::begin(interior_rings),
boost::end(interior_rings),
unary_predicate_type(segment, strategy));
}
@@ -175,17 +169,16 @@ public:
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) )
if (! disjoint_range_segment_or_box
<
typename geometry::ring_type<Polygon>::type,
Segment
>::apply(geometry::exterior_ring(polygon), segment, strategy))
{
return false;
}
if ( !check_interior_rings(geometry::interior_rings(polygon), segment, strategy) )
if (! check_interior_rings(geometry::interior_rings(polygon), segment, strategy))
{
return false;
}
@@ -193,8 +186,7 @@ public:
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>());
return ! geometry::covered_by(p, polygon, strategy);
}
};
@@ -222,10 +214,7 @@ struct disjoint_segment_areal<Segment, Ring, ring_tag>
Ring const& ring,
IntersectionStrategy const& strategy)
{
if ( !disjoint_range_segment_or_box
<
Ring, closure<Ring>::value, Segment
>::apply(ring, segment, strategy) )
if (! disjoint_range_segment_or_box<Ring, Segment>::apply(ring, segment, strategy))
{
return false;
}
@@ -233,8 +222,7 @@ struct disjoint_segment_areal<Segment, Ring, ring_tag>
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>());
return ! geometry::covered_by(p, ring, strategy);
}
};

View File

@@ -5,8 +5,8 @@
// 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.
// 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
@@ -24,9 +24,6 @@
#include <cstddef>
#include <deque>
#include <boost/range.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -34,10 +31,12 @@
#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/geometries/helper_geometry.hpp>
#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
@@ -59,28 +58,17 @@ struct disjoint_segment
{
typedef typename point_type<Segment1>::type point_type;
// We don't need to rescale to detect disjointness
typedef no_rescale_policy rescale_policy_type;
rescale_policy_type robust_policy;
typedef segment_intersection_points
<
point_type,
typename segment_ratio_type
<
point_type,
rescale_policy_type
>::type
> intersection_return_type;
typedef segment_intersection_points<point_type> intersection_return_type;
typedef policies::relate::segments_intersection_points
<
intersection_return_type
> intersection_policy;
intersection_return_type is = strategy.apply(segment1, segment2,
intersection_policy(),
robust_policy);
detail::segment_as_subrange<Segment1> sub_range1(segment1);
detail::segment_as_subrange<Segment2> sub_range2(segment2);
intersection_return_type is = strategy.relate().apply(sub_range1, sub_range2,
intersection_policy());
return is.count == 0;
}
@@ -93,6 +81,7 @@ struct assign_disjoint_policy
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;
};
@@ -104,21 +93,21 @@ struct disjoint_linear
Geometry2 const& geometry2,
Strategy const& strategy)
{
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef detail::no_rescale_policy rescale_policy_type;
typedef typename geometry::segment_ratio_type
using point_type = typename geometry::point_type<Geometry1>::type;
using mutable_point_type = typename helper_geometry<point_type>::type;
using ratio_type = geometry::segment_ratio
<
point_type, rescale_policy_type
>::type segment_ratio_type;
typedef overlay::turn_info
typename coordinate_type<point_type>::type
> ;
using turn_info_type = overlay::turn_info
<
point_type,
segment_ratio_type,
mutable_point_type,
ratio_type,
typename detail::get_turns::turn_operation_type
<
Geometry1, Geometry2, segment_ratio_type
Geometry1, Geometry2, mutable_point_type, ratio_type
>::type
> turn_info_type;
>;
std::deque<turn_info_type> turns;
@@ -139,7 +128,7 @@ struct disjoint_linear
Geometry1, Geometry2, assign_disjoint_policy
>
>::apply(0, geometry1, 1, geometry2,
strategy, rescale_policy_type(), turns, interrupt_policy);
strategy, detail::no_rescale_policy(), turns, interrupt_policy);
return !interrupt_policy.has_intersections;
}

View File

@@ -5,8 +5,8 @@
// 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.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021, 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
@@ -21,19 +21,14 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
#include <boost/range.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/views/closeable_view.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
@@ -47,10 +42,41 @@ namespace detail { namespace disjoint
template
<
typename Range,
closure_selector Closure,
typename SegmentOrBox
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 <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);
}
};
template <typename Range, typename SegmentOrBox>
struct disjoint_range_segment_or_box
{
template <typename Strategy>
@@ -58,24 +84,12 @@ struct disjoint_range_segment_or_box
SegmentOrBox const& segment_or_box,
Strategy const& strategy)
{
typedef typename closeable_view<Range const, Closure>::type view_type;
using point_type = typename point_type<Range>::type;
using range_segment = typename geometry::model::referring_segment<point_type const>;
typedef typename ::boost::range_value<view_type>::type point_type;
typedef typename ::boost::range_iterator
<
view_type const
>::type const_iterator;
detail::closed_view<Range const> const view(range);
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);
auto const count = ::boost::size(view);
if ( count == 0 )
{
@@ -83,22 +97,22 @@ struct disjoint_range_segment_or_box
}
else if ( count == 1 )
{
return dispatch::disjoint
return disjoint_point_segment_or_box
<
point_type, SegmentOrBox
>::apply(geometry::range::front<view_type const>(view),
segment_or_box,
strategy.template get_point_in_geometry_strategy<Range, SegmentOrBox>());
SegmentOrBox
>::apply(range::front(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);
auto it0 = ::boost::begin(view);
auto it1 = ::boost::begin(view) + 1;
auto const last = ::boost::end(view);
for ( ; it1 != last ; ++it0, ++it1 )
{
range_segment rng_segment(*it0, *it1);
point_type const& p0 = *it0;
point_type const& p1 = *it1;
range_segment rng_segment(p0, p1);
if ( !dispatch::disjoint
<
range_segment, SegmentOrBox
@@ -128,7 +142,7 @@ struct disjoint_linear_segment_or_box
template <typename Linestring, typename SegmentOrBox>
struct disjoint_linear_segment_or_box<Linestring, SegmentOrBox, linestring_tag>
: disjoint_range_segment_or_box<Linestring, closed, SegmentOrBox>
: disjoint_range_segment_or_box<Linestring, SegmentOrBox>
{};

View File

@@ -2,7 +2,9 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014-2018, Oracle and/or its affiliates.
// Copyright (c) 2014-2023, 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
@@ -15,8 +17,10 @@
#include <algorithm>
#include <vector>
#include <boost/range.hpp>
#include <boost/mpl/assert.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/core/tag.hpp>
@@ -29,7 +33,6 @@
#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>
@@ -42,6 +45,12 @@
#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
{
@@ -51,29 +60,28 @@ namespace detail { namespace disjoint
{
template <typename MultiPoint1, typename MultiPoint2>
class multipoint_multipoint
{
private:
template <typename Iterator>
class unary_disjoint_predicate
: geometry::less<>
template <typename Iterator, typename Strategy>
class unary_not_disjoint_predicate
: geometry::less<void, -1, Strategy>
{
private:
typedef geometry::less<> base_type;
using less_type = geometry::less<void, -1, Strategy>;
public:
unary_disjoint_predicate(Iterator first, Iterator last)
: base_type(), m_first(first), m_last(last)
unary_not_disjoint_predicate(Iterator first, Iterator last)
: less_type(), m_first(first), m_last(last)
{}
template <typename Point>
inline bool apply(Point const& point) const
inline bool operator()(Point const& point) const
{
return !std::binary_search(m_first,
m_last,
point,
static_cast<base_type const&>(*this));
return std::binary_search(m_first,
m_last,
point,
static_cast<less_type const&>(*this));
}
private:
@@ -81,29 +89,30 @@ private:
};
public:
template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
static inline bool apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2)
MultiPoint2 const& multipoint2,
Strategy const&)
{
BOOST_GEOMETRY_ASSERT( boost::size(multipoint1) <= boost::size(multipoint2) );
typedef typename boost::range_value<MultiPoint1>::type point1_type;
using less_type = geometry::less<void, -1, Strategy>;
using point1_type = typename boost::range_value<MultiPoint1>::type;
std::vector<point1_type> points1(boost::begin(multipoint1),
boost::end(multipoint1));
std::sort(points1.begin(), points1.end(), geometry::less<>());
std::sort(points1.begin(), points1.end(), less_type());
typedef unary_disjoint_predicate
using predicate_type = unary_not_disjoint_predicate
<
typename std::vector<point1_type>::const_iterator
> predicate_type;
typename std::vector<point1_type>::const_iterator,
Strategy
>;
return check_iterator_range
<
predicate_type
>::apply(boost::begin(multipoint2),
boost::end(multipoint2),
predicate_type(points1.begin(), points1.end()));
return none_of(boost::begin(multipoint2),
boost::end(multipoint2),
predicate_type(points1.begin(), points1.end()));
}
};
@@ -112,65 +121,78 @@ template <typename MultiPoint, typename Linear>
class multipoint_linear
{
private:
template <typename Strategy>
struct expand_box_point
{
explicit expand_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
static inline void apply(Box& total, Point const& point)
void apply(Box& total, Point const& point) const
{
geometry::expand(total, point);
geometry::expand(total, point, m_strategy);
}
Strategy const& m_strategy;
};
template <typename EnvelopeStrategy>
template <typename Strategy>
struct expand_box_segment
{
explicit expand_box_segment(EnvelopeStrategy const& strategy)
explicit expand_box_segment(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Segment>
inline void apply(Box& total, Segment const& segment) const
void apply(Box& total, Segment const& segment) const
{
geometry::expand(total,
geometry::return_envelope<Box>(segment, m_strategy));
geometry::return_envelope<Box>(segment, m_strategy),
m_strategy);
}
EnvelopeStrategy const& m_strategy;
Strategy const& m_strategy;
};
template <typename DisjointPointBoxStrategy>
template <typename Strategy>
struct overlaps_box_point
{
explicit overlaps_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
static inline bool apply(Box const& box, Point const& point)
bool apply(Box const& box, Point const& point) const
{
// The default strategy is enough in this case
return ! detail::disjoint::disjoint_point_box(point, box,
DisjointPointBoxStrategy());
m_strategy);
}
Strategy const& m_strategy;
};
template <typename DisjointStrategy>
template <typename Strategy>
struct overlaps_box_segment
{
explicit overlaps_box_segment(DisjointStrategy const& strategy)
explicit overlaps_box_segment(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Segment>
inline bool apply(Box const& box, Segment const& segment) const
bool apply(Box const& box, Segment const& segment) const
{
return ! dispatch::disjoint<Segment, Box>::apply(segment, box, m_strategy);
}
DisjointStrategy const& m_strategy;
Strategy const& m_strategy;
};
template <typename PtSegStrategy>
template <typename Strategy>
class item_visitor_type
{
public:
item_visitor_type(PtSegStrategy const& strategy)
item_visitor_type(Strategy const& strategy)
: m_intersection_found(false)
, m_strategy(strategy)
{}
@@ -191,7 +213,7 @@ private:
private:
bool m_intersection_found;
PtSegStrategy const& m_strategy;
Strategy const& m_strategy;
};
// structs for partition -- end
@@ -225,10 +247,6 @@ public:
{
item_visitor_type<Strategy> visitor(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_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.
@@ -238,16 +256,17 @@ public:
<
geometry::model::box<typename point_type<MultiPoint>::type>
>::apply(multipoint, segment_range(linear), visitor,
expand_box_point(),
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()));
expand_box_point<Strategy>(strategy),
overlaps_box_point<Strategy>(strategy),
expand_box_segment<Strategy>(strategy),
overlaps_box_segment<Strategy>(strategy));
return ! visitor.intersection_found();
}
template <typename Strategy>
static inline bool apply(Linear const& linear, MultiPoint const& multipoint, Strategy const& strategy)
static inline bool apply(Linear const& linear, MultiPoint const& multipoint,
Strategy const& strategy)
{
return apply(multipoint, linear, strategy);
}
@@ -263,21 +282,18 @@ public:
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::envelope(single_geometry, box2, 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 )
for (auto 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())
if (! detail::disjoint::disjoint_point_box(*it, box2, strategy)
&& ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy))
{
return false;
@@ -288,7 +304,8 @@ public:
}
template <typename Strategy>
static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point, Strategy const& strategy)
static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point,
Strategy const& strategy)
{
return apply(multi_point, single_geometry, strategy);
}
@@ -299,54 +316,77 @@ template <typename MultiPoint, typename MultiGeometry>
class multi_point_multi_geometry
{
private:
template <typename Strategy>
struct expand_box_point
{
explicit expand_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
static inline void apply(Box& total, Point const& point)
void apply(Box& total, Point const& point) const
{
geometry::expand(total, point);
geometry::expand(total, point, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct expand_box_box_pair
{
explicit expand_box_box_pair(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename BoxPair>
inline void apply(Box& total, BoxPair const& box_pair) const
void apply(Box& total, BoxPair const& box_pair) const
{
geometry::expand(total, box_pair.first);
geometry::expand(total, box_pair.first, m_strategy);
}
Strategy const& m_strategy;
};
template <typename DisjointPointBoxStrategy>
template <typename Strategy>
struct overlaps_box_point
{
explicit overlaps_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
static inline bool apply(Box const& box, Point const& point)
bool apply(Box const& box, Point const& point) const
{
// The default strategy is enough for Point/Box
return ! detail::disjoint::disjoint_point_box(point, box,
DisjointPointBoxStrategy());
return ! detail::disjoint::disjoint_point_box(point, box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename DisjointBoxBoxStrategy>
template <typename Strategy>
struct overlaps_box_box_pair
{
explicit overlaps_box_box_pair(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename BoxPair>
inline bool apply(Box const& box, BoxPair const& box_pair) const
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());
m_strategy);
}
Strategy const& m_strategy;
};
template <typename PtSegStrategy>
template <typename Strategy>
class item_visitor_type
{
public:
item_visitor_type(MultiGeometry const& multi_geometry,
PtSegStrategy const& strategy)
Strategy const& strategy)
: m_intersection_found(false)
, m_multi_geometry(multi_geometry)
, m_strategy(strategy)
@@ -355,14 +395,15 @@ private:
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))
&& ! detail::disjoint::disjoint_point_box(point, box_pair.first, m_strategy)
&& ! dispatch::disjoint
<
Point, single_type
>::apply(point, range::at(m_multi_geometry, box_pair.second), m_strategy))
{
m_intersection_found = true;
return false;
@@ -375,7 +416,7 @@ private:
private:
bool m_intersection_found;
MultiGeometry const& m_multi_geometry;
PtSegStrategy const& m_strategy;
Strategy const& m_strategy;
};
// structs for partition -- end
@@ -389,37 +430,25 @@ public:
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::envelope(range::at(multi_geometry, i), boxes[i].first, strategy);
geometry::detail::expand_by_epsilon(boxes[i].first);
boxes[i].second = i;
}
item_visitor_type<Strategy> visitor(multi_geometry, strategy);
typedef overlaps_box_point
<
typename Strategy::disjoint_point_box_strategy_type
> overlaps_box_point_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(),
overlaps_box_point_type(),
expand_box_box_pair(),
overlaps_box_box_pair_type());
expand_box_point<Strategy>(strategy),
overlaps_box_point<Strategy>(strategy),
expand_box_box_pair<Strategy>(strategy),
overlaps_box_box_pair<Strategy>(strategy));
return ! visitor.intersection_found();
}
@@ -493,20 +522,16 @@ struct disjoint
template <typename Strategy>
static inline bool apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
Strategy const& )
Strategy const& strategy)
{
if ( boost::size(multipoint2) < boost::size(multipoint1) )
{
return detail::disjoint::multipoint_multipoint
<
MultiPoint2, MultiPoint1
>::apply(multipoint2, multipoint1);
}
::apply(multipoint2, multipoint1, strategy);
}
return detail::disjoint::multipoint_multipoint
<
MultiPoint1, MultiPoint2
>::apply(multipoint1, multipoint2);
::apply(multipoint1, multipoint2, strategy);
}
};

View File

@@ -1,7 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Copyright (c) 2014-2023, 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
@@ -11,9 +12,12 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
#include <boost/range.hpp>
#include <algorithm>
#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>
@@ -31,13 +35,13 @@ class unary_disjoint_geometry_to_query_geometry
{
public:
unary_disjoint_geometry_to_query_geometry(Geometry const& geometry,
Strategy const& strategy)
Strategy const& strategy)
: m_geometry(geometry)
, m_strategy(strategy)
{}
template <typename QueryGeometry>
inline bool apply(QueryGeometry const& query_geometry) const
inline bool operator()(QueryGeometry const& query_geometry) const
{
return BinaryPredicate::apply(query_geometry, m_geometry, m_strategy);
}
@@ -56,7 +60,7 @@ struct multirange_constant_size_geometry
ConstantSizeGeometry const& constant_size_geometry,
Strategy const& strategy)
{
typedef unary_disjoint_geometry_to_query_geometry
using disjoint = unary_disjoint_geometry_to_query_geometry
<
ConstantSizeGeometry,
Strategy,
@@ -65,13 +69,11 @@ struct multirange_constant_size_geometry
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));
return std::all_of(boost::begin(multirange),
boost::end(multirange),
disjoint(constant_size_geometry, strategy));
}
template <typename Strategy>

View File

@@ -5,9 +5,8 @@
// 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.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021, 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
@@ -23,12 +22,13 @@
#include <cstddef>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#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>
#include <boost/geometry/strategies/detail.hpp>
namespace boost { namespace geometry
{
@@ -41,8 +41,26 @@ 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& )
template
<
typename Point, typename Box, typename Strategy,
std::enable_if_t<strategies::detail::is_umbrella_strategy<Strategy>::value, int> = 0
>
inline bool disjoint_point_box(Point const& point, Box const& box,
Strategy const& strategy)
{
typedef decltype(strategy.covered_by(point, box)) strategy_type;
// ! covered_by(point, box)
return ! strategy_type::apply(point, box);
}
template
<
typename Point, typename Box, typename Strategy,
std::enable_if_t<! strategies::detail::is_umbrella_strategy<Strategy>::value, int> = 0
>
inline bool disjoint_point_box(Point const& point, Box const& box,
Strategy const& )
{
// ! covered_by(point, box)
return ! Strategy::apply(point, box);
@@ -62,10 +80,12 @@ 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& )
static inline bool apply(Point const& point, Box const& box,
Strategy const& strategy)
{
typedef decltype(strategy.covered_by(point, box)) strategy_type;
// ! covered_by(point, box)
return ! Strategy::apply(point, box);
return ! strategy_type::apply(point, box);
}
};

View File

@@ -5,8 +5,8 @@
// 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.
// This file was modified by Oracle on 2013-2022.
// Modifications copyright (c) 2013-2022, 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
@@ -21,7 +21,7 @@
#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/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>

View File

@@ -5,8 +5,8 @@
// 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.
// 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
@@ -22,11 +22,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
#include <cstddef>
#include <type_traits>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/strategies/detail.hpp>
// For backward compatibility
#include <boost/geometry/strategies/disjoint.hpp>
#include <boost/geometry/strategies/cartesian/point_in_point.hpp>
@@ -46,10 +49,28 @@ 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>
template
<
typename Point1, typename Point2, typename Strategy,
std::enable_if_t<strategies::detail::is_umbrella_strategy<Strategy>::value, int> = 0
>
inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2,
Strategy const& strategy)
{
typedef decltype(strategy.relate(point1, point2)) strategy_type;
// ! within(point1, point2)
return ! strategy_type::apply(point1, point2);
}
template
<
typename Point1, typename Point2, typename Strategy,
std::enable_if_t<! strategies::detail::is_umbrella_strategy<Strategy>::value, int> = 0
>
inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2,
Strategy const& )
{
// ! within(point1, point2)
return ! Strategy::apply(point1, point2);
}
@@ -68,9 +89,11 @@ 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& )
Strategy const& strategy)
{
return ! Strategy::apply(point1, point2);
typedef decltype(strategy.relate(point1, point2)) strategy_type;
// ! within(point1, point2)
return ! strategy_type::apply(point1, point2);
}
};

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2019.
// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
// This file was modified by Oracle on 2013-2021.
// Modifications copyright (c) 2013-2021, 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
@@ -33,14 +33,13 @@
#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/strategies/spherical/envelope_segment.hpp>
#include <boost/geometry/strategy/spherical/envelope_segment.hpp>
namespace boost { namespace geometry
{
@@ -181,12 +180,31 @@ struct disjoint_segment_box_sphere_or_spheroid
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;
int s0 = formula::azimuth_side_value(alp1, a_b0);
int s1 = formula::azimuth_side_value(alp1, a_b1);
int s2 = formula::azimuth_side_value(alp1, a_b2);
int s3 = formula::azimuth_side_value(alp1, a_b3);
if (!(b0 && b1 && b2 && b3) && (b0 || b1 || b2 || b3))
if (s0 == 0 || s1 == 0 || s2 == 0 || s3 == 0)
{
return disjoint_info::intersect;
}
bool s0_positive = s0 > 0;
bool s1_positive = s1 > 0;
bool s2_positive = s2 > 0;
bool s3_positive = s3 > 0;
bool all_positive = s0_positive && s1_positive && s2_positive && s3_positive;
bool all_non_positive = !(s0_positive || s1_positive || s2_positive || s3_positive);
bool vertex_north = lat1 + lat2 > 0;
if ((all_positive && vertex_north) || (all_non_positive && !vertex_north))
{
return disjoint_info::disjoint_no_vertex;
}
if (!all_positive && !all_non_positive)
{
return disjoint_info::intersect;
}
@@ -196,14 +214,13 @@ struct disjoint_segment_box_sphere_or_spheroid
// 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)))
if ((lat1 < b_lat_min && vertex_north)
|| (lat1 > b_lat_max && !vertex_north))
{
CT b_lat_below; //latitude of box closest to equator
if (lat_sum > CT(0))
if (vertex_north)
{
vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
b_lat_below = b_lat_min;
@@ -247,7 +264,7 @@ struct disjoint_segment_box
Box const& box,
Strategy const& strategy)
{
return strategy.apply(segment, box);
return strategy.disjoint(segment, box).apply(segment, box);
}
};

View File

@@ -1,333 +0,0 @@
// 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

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -29,23 +30,17 @@ namespace dispatch
{
template <typename Box1, typename Box2, typename Strategy>
template <typename Box1, typename Box2, typename Strategies>
struct distance
<
Box1, Box2, Strategy, box_tag, box_tag,
Box1, Box2, Strategies, 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)
static inline auto apply(Box1 const& box1, Box2 const& box2, Strategies const& strategies)
{
boost::ignore_unused(strategy);
return strategy.apply(box1, box2);
boost::ignore_unused(strategies);
return strategies.distance(box1, box2).apply(box1, box2);
}
};

View File

@@ -1,157 +0,0 @@
// 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_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 Linear, typename Box>
struct default_strategy<Linear, Box, segment_tag, box_tag, false>
: strategy::distance::services::default_strategy
<
segment_tag, box_tag,
typename point_type<Linear>::type,
typename point_type<Box>::type
>
{};
template <typename Linear, typename Box>
struct default_strategy<Linear, Box, linear_tag, box_tag, false>
: strategy::distance::services::default_strategy
<
segment_tag, box_tag,
typename point_type<Linear>::type,
typename point_type<Box>::type
>
{};
// 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

View File

@@ -0,0 +1,237 @@
// Boost.Geometry
// Copyright (c) 2021 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_DISTANCE_GEOMETRY_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_COLLECTION_HPP
#include <vector>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/distance_result.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Geometry, typename GeometryCollection, typename Strategies>
inline auto geometry_to_collection(Geometry const& geometry,
GeometryCollection const& collection,
Strategies const& strategies)
{
using result_t = typename geometry::distance_result<Geometry, GeometryCollection, Strategies>::type;
result_t result = 0;
bool is_first = true;
detail::visit_breadth_first([&](auto const& g)
{
result_t r = dispatch::distance
<
Geometry, util::remove_cref_t<decltype(g)>, Strategies
>::apply(geometry, g, strategies);
if (is_first)
{
result = r;
is_first = false;
}
else if (r < result)
{
result = r;
}
return result > result_t(0);
}, collection);
return result;
}
template <typename GeometryCollection1, typename GeometryCollection2, typename Strategies>
inline auto collection_to_collection(GeometryCollection1 const& collection1,
GeometryCollection2 const& collection2,
Strategies const& strategies)
{
using result_t = typename geometry::distance_result<GeometryCollection1, GeometryCollection2, Strategies>::type;
using point1_t = typename geometry::point_type<GeometryCollection1>::type;
using box1_t = model::box<point1_t>;
using point2_t = typename geometry::point_type<GeometryCollection2>::type;
using box2_t = model::box<point2_t>;
using rtree_value_t = std::pair<box1_t, typename boost::range_iterator<GeometryCollection1 const>::type>;
using rtree_params_t = index::parameters<index::rstar<4>, Strategies>;
using rtree_t = index::rtree<rtree_value_t, rtree_params_t>;
rtree_params_t rtree_params(index::rstar<4>(), strategies);
rtree_t rtree(rtree_params);
// Build rtree of boxes and iterators of elements of GC1
// TODO: replace this with visit_breadth_first_iterator to avoid creating an unnecessary container?
{
std::vector<rtree_value_t> values;
visit_breadth_first_impl<true>::apply([&](auto & g1, auto it)
{
box1_t b1 = geometry::return_envelope<box1_t>(g1, strategies);
geometry::detail::expand_by_epsilon(b1);
values.emplace_back(b1, it);
return true;
}, collection1);
rtree_t rt(values.begin(), values.end(), rtree_params);
rtree = std::move(rt);
}
result_t const zero = 0;
auto const rtree_qend = rtree.qend();
result_t result = 0;
bool is_first = true;
visit_breadth_first([&](auto const& g2)
{
box2_t b2 = geometry::return_envelope<box2_t>(g2, strategies);
geometry::detail::expand_by_epsilon(b2);
for (auto it = rtree.qbegin(index::nearest(b2, rtree.size())) ; it != rtree_qend ; ++it)
{
// If the distance between boxes is greater than or equal to previously found
// distance between geometries then stop processing the current b2 because no
// closer b1 will be found
if (! is_first)
{
result_t const bd = dispatch::distance
<
box1_t, box2_t, Strategies
>::apply(it->first, b2, strategies);
if (bd >= result)
{
break;
}
}
// Boxes are closer than the previously found distance (or it's the first time),
// calculate the new distance between geometries and check if it's closer (or assign it).
traits::iter_visit<GeometryCollection1>::apply([&](auto const& g1)
{
result_t const d = dispatch::distance
<
util::remove_cref_t<decltype(g1)>, util::remove_cref_t<decltype(g2)>,
Strategies
>::apply(g1, g2, strategies);
if (is_first)
{
result = d;
is_first = false;
}
else if (d < result)
{
result = d;
}
}, it->second);
// The smallest possible distance found, end searching.
if (! is_first && result <= zero)
{
return false;
}
}
// Just in case
return is_first || result > zero;
}, collection2);
return result;
}
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry, typename GeometryCollection, typename Strategies, typename Tag1
>
struct distance
<
Geometry, GeometryCollection, Strategies,
Tag1, geometry_collection_tag, void, false
>
{
static inline auto apply(Geometry const& geometry,
GeometryCollection const& collection,
Strategies const& strategies)
{
assert_dimension_equal<Geometry, GeometryCollection>();
return detail::distance::geometry_to_collection(geometry, collection, strategies);
}
};
template
<
typename GeometryCollection, typename Geometry, typename Strategies, typename Tag2
>
struct distance
<
GeometryCollection, Geometry, Strategies,
geometry_collection_tag, Tag2, void, false
>
{
static inline auto apply(GeometryCollection const& collection,
Geometry const& geometry,
Strategies const& strategies)
{
assert_dimension_equal<Geometry, GeometryCollection>();
return detail::distance::geometry_to_collection(geometry, collection, strategies);
}
};
template
<
typename GeometryCollection1, typename GeometryCollection2, typename Strategies
>
struct distance
<
GeometryCollection1, GeometryCollection2, Strategies,
geometry_collection_tag, geometry_collection_tag, void, false
>
{
static inline auto apply(GeometryCollection1 const& collection1,
GeometryCollection2 const& collection2,
Strategies const& strategies)
{
assert_dimension_equal<GeometryCollection1, GeometryCollection2>();
// Build the rtree for the smaller GC (ignoring recursive GCs)
return boost::size(collection1) <= boost::size(collection2)
? detail::distance::collection_to_collection(collection1, collection2, strategies)
: detail::distance::collection_to_collection(collection2, collection1, strategies);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -12,28 +13,27 @@
#include <iterator>
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.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/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/num_points.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/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/util/condition.hpp>
@@ -54,7 +54,7 @@ template
>
struct segment_or_box_point_range_closure
: not_implemented<SegmentOrBox>
{};
{};
template <typename Segment>
struct segment_or_box_point_range_closure<Segment, segment_tag>
@@ -74,7 +74,7 @@ template
<
typename Geometry,
typename SegmentOrBox,
typename Strategy,
typename Strategies,
typename Tag = typename tag<Geometry>::type
>
class geometry_to_segment_or_box
@@ -82,28 +82,18 @@ 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 distance::strategy_t<Geometry, SegmentOrBox, Strategies> strategy_type;
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
segment_or_box_point_range_closure<SegmentOrBox>::value
> 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;
typedef distance::creturn_t<Geometry, SegmentOrBox, Strategies> comparable_return_type;
// assign the new minimum value for an iterator of the point range
// of a segment or a box
@@ -165,45 +155,34 @@ private:
}
};
public:
typedef typename strategy::distance::services::return_type
<
Strategy,
typename point_type<Geometry>::type,
segment_or_box_point
>::type return_type;
typedef distance::return_t<Geometry, SegmentOrBox, Strategies> return_type;
static inline return_type apply(Geometry const& geometry,
SegmentOrBox const& segment_or_box,
Strategy const& strategy,
Strategies const& strategies,
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
&& geometry::intersects(geometry, segment_or_box))
&& geometry::intersects(geometry, segment_or_box, strategies))
{
return 0;
return return_type(0);
}
comparable_strategy cstrategy =
strategy::distance::services::get_comparable
<
Strategy
>::apply(strategy);
strategy_type const strategy = strategies.distance(geometry, segment_or_box);
auto const cstrategy = strategy::distance::services::get_comparable
<
strategy_type
>::apply(strategy);
// get all points of the segment or the box
std::vector<segment_or_box_point>
@@ -211,32 +190,27 @@ public:
assign_segment_or_box_points
<
SegmentOrBox,
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;
auto pit_min = points_begin(geometry);
auto it_min1 = boost::const_begin(seg_or_box_points);
auto it_min2 = it_min1 + 1;
bool first = true;
for (point_iterator_type pit = points_begin(geometry);
for (auto pit = pit_min;
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);
auto 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)
{
@@ -251,10 +225,10 @@ public:
// segments of the geometry
comparable_return_type cd_min2(0);
segment_iterator_type sit_min;
seg_or_box_const_iterator it_min;
auto it_min = boost::const_begin(seg_or_box_points);
first = true;
for (seg_or_box_const_iterator it = boost::const_begin(seg_or_box_points);
for (auto it = boost::const_begin(seg_or_box_points);
it != boost::const_end(seg_or_box_points); ++it, first = false)
{
comparable_return_type cd;
@@ -273,7 +247,7 @@ public:
}
}
if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
if (BOOST_GEOMETRY_CONDITION(is_comparable<strategy_type>::value))
{
return (std::min)(cd_min1, cd_min2);
}
@@ -291,71 +265,53 @@ public:
<
segment_iterator_type
>::value_type,
Strategy
>::apply(*it_min, *sit_min, strategy);
Strategies
>::apply(*it_min, *sit_min, strategies);
}
}
static inline return_type
apply(SegmentOrBox const& segment_or_box, Geometry const& geometry,
Strategy const& strategy, bool check_intersection = true)
static inline return_type apply(SegmentOrBox const& segment_or_box, Geometry const& geometry,
Strategies const& strategies, bool check_intersection = true)
{
return apply(geometry, segment_or_box, strategy, check_intersection);
return apply(geometry, segment_or_box, strategies, check_intersection);
}
};
template <typename MultiPoint, typename SegmentOrBox, typename Strategy>
template <typename MultiPoint, typename SegmentOrBox, typename Strategies>
class geometry_to_segment_or_box
<
MultiPoint, SegmentOrBox, Strategy, multi_point_tag
MultiPoint, SegmentOrBox, Strategies, 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;
typedef distance::strategy_t<MultiPoint, SegmentOrBox, Strategies> strategy_type;
public:
typedef typename strategy::distance::services::return_type
<
Strategy,
typename point_type<SegmentOrBox>::type,
typename point_type<MultiPoint>::type
>::type return_type;
typedef distance::return_t<MultiPoint, SegmentOrBox, Strategies> return_type;
static inline return_type apply(MultiPoint const& multipoint,
SegmentOrBox const& segment_or_box,
Strategy const& strategy)
Strategies const& strategies)
{
namespace sds = strategy::distance::services;
distance::creturn_t<MultiPoint, SegmentOrBox, Strategies> cd_min;
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
auto const it_min
= geometry_to_range::apply(segment_or_box,
boost::begin(multipoint),
boost::end(multipoint),
sds::get_comparable
strategy::distance::services::get_comparable
<
Strategy
>::apply(strategy),
strategy_type
>::apply(strategies.distance(multipoint, segment_or_box)),
cd_min);
return
is_comparable<Strategy>::value
is_comparable<strategy_type>::value
?
cd_min
:
@@ -363,8 +319,8 @@ public:
<
typename point_type<MultiPoint>::type,
SegmentOrBox,
Strategy
>::apply(*it_min, segment_or_box, strategy);
Strategies
>::apply(*it_min, segment_or_box, strategies);
}
};

View File

@@ -5,11 +5,11 @@
// 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.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, 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.
@@ -27,11 +27,15 @@
#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_collection.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>
#include <boost/geometry/strategies/distance/backward_compatibility.hpp>
#include <boost/geometry/strategies/distance/cartesian.hpp>
#include <boost/geometry/strategies/distance/geographic.hpp>
#include <boost/geometry/strategies/distance/spherical.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP

View File

@@ -6,9 +6,8 @@
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2014, 2018.
// Modifications copyright (c) 2014-2018, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, 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
@@ -24,23 +23,22 @@
#include <boost/concept_check.hpp>
#include <boost/mpl/always.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/distance.hpp>
// TODO: move these to algorithms
#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>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/distance/services.hpp>
namespace boost { namespace geometry
@@ -66,17 +64,8 @@ struct distance
>
: 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)
static inline auto apply(Geometry1 const& g1, Geometry2 const& g2,
Strategy const& strategy)
{
return distance
<
@@ -95,14 +84,17 @@ struct distance
namespace resolve_strategy
{
template <typename Strategy>
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
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)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return dispatch::distance
<
@@ -111,17 +103,69 @@ struct distance
}
};
template <typename Strategy>
struct is_strategy_converter_specialized
{
typedef strategies::distance::services::strategy_converter<Strategy> converter;
static const bool value = ! std::is_same
<
decltype(converter::get(std::declval<Strategy>())),
strategies::detail::not_implemented
>::value;
};
template <typename Strategy>
struct distance<Strategy, false>
{
template
<
typename Geometry1, typename Geometry2, typename S,
std::enable_if_t<is_strategy_converter_specialized<S>::value, int> = 0
>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
S const& strategy)
{
typedef strategies::distance::services::strategy_converter<Strategy> converter;
typedef decltype(converter::get(strategy)) strategy_type;
return dispatch::distance
<
Geometry1, Geometry2, strategy_type
>::apply(geometry1, geometry2, converter::get(strategy));
}
template
<
typename Geometry1, typename Geometry2, typename S,
std::enable_if_t<! is_strategy_converter_specialized<S>::value, int> = 0
>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
S const& strategy)
{
typedef strategies::distance::services::custom_strategy_converter
<
Geometry1, Geometry2, Strategy
> converter;
typedef decltype(converter::get(strategy)) strategy_type;
return dispatch::distance
<
Geometry1, Geometry2, strategy_type
>::apply(geometry1, geometry2, converter::get(strategy));
}
};
template <>
struct distance<default_strategy>
struct distance<default_strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline
typename distance_result<Geometry1, Geometry2, default_strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename detail::distance::default_strategy
typedef typename strategies::distance::services::default_strategy
<
Geometry1, Geometry2
>::type strategy_type;
@@ -136,18 +180,22 @@ struct distance<default_strategy>
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry1, typename Geometry2>
template
<
typename Geometry1, typename Geometry2,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct distance
{
template <typename Strategy>
static inline typename distance_result<Geometry1, Geometry2, Strategy>::type
apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::distance
<
@@ -157,174 +205,72 @@ struct distance
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct distance<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
struct distance<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Strategy>
struct visitor: static_visitor
<
typename distance_result
<
variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Geometry2,
Strategy
>::type
>
static inline auto apply(DynamicGeometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
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
using result_t = typename geometry::distance_result<DynamicGeometry1, Geometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
{
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);
result = resolve_strategy::distance
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct distance<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
struct distance<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag>
{
template <typename Strategy>
struct visitor: static_visitor
<
typename distance_result
<
Geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)>,
Strategy
>::type
>
static inline auto apply(Geometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
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
using result_t = typename geometry::distance_result<Geometry1, DynamicGeometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
{
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);
result = resolve_strategy::distance
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
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 DynamicGeometry1, typename DynamicGeometry2>
struct distance<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag>
{
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
>
static inline auto apply(DynamicGeometry1 const& geometry1,
DynamicGeometry2 const& geometry2,
Strategy const& strategy)
{
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
using result_t = typename geometry::distance_result<DynamicGeometry1, DynamicGeometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
{
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);
result = resolve_strategy::distance
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
@@ -364,10 +310,9 @@ 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)
inline auto distance(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
@@ -375,7 +320,7 @@ distance(Geometry1 const& geometry1,
detail::throw_on_empty_input(geometry1);
detail::throw_on_empty_input(geometry2);
return resolve_variant::distance
return resolve_dynamic::distance
<
Geometry1,
Geometry2
@@ -397,13 +342,9 @@ distance(Geometry1 const& geometry1,
\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)
inline auto distance(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return geometry::distance(geometry1, geometry2, default_strategy());
}

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// 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
@@ -10,7 +11,8 @@
#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
#include <boost/type_traits/is_same.hpp>
#include <type_traits>
#include <boost/geometry/strategies/distance.hpp>
@@ -26,7 +28,7 @@ namespace detail { namespace distance
// metafunction to determine is a strategy is comparable or not
template <typename Strategy>
struct is_comparable
: boost::is_same
: std::is_same
<
Strategy,
typename strategy::distance::services::comparable_type

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -10,13 +11,14 @@
#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/algorithms/detail/distance/linear_to_linear.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/intersects.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
{
@@ -26,63 +28,53 @@ namespace detail { namespace distance
{
template <typename Linear, typename Areal, typename Strategy>
template <typename Linear, typename Areal, typename Strategies>
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;
typedef distance::return_t<Linear, Areal, Strategies> return_type;
static inline return_type apply(Linear const& linear,
Areal const& areal,
Strategy const& strategy)
Strategies const& strategies)
{
if ( geometry::intersects(linear, areal) )
if ( geometry::intersects(linear, areal, strategies) )
{
return 0;
return return_type(0);
}
return linear_to_linear
<
Linear, Areal, Strategy
>::apply(linear, areal, strategy, false);
Linear, Areal, Strategies
>::apply(linear, areal, strategies, false);
}
static inline return_type apply(Areal const& areal,
Linear const& linear,
Strategy const& strategy)
Strategies const& strategies)
{
return apply(linear, areal, strategy);
return apply(linear, areal, strategies);
}
};
template <typename Areal1, typename Areal2, typename Strategy>
template <typename Areal1, typename Areal2, typename Strategies>
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;
typedef distance::return_t<Areal1, Areal2, Strategies> return_type;
static inline return_type apply(Areal1 const& areal1,
Areal2 const& areal2,
Strategy const& strategy)
Strategies const& strategies)
{
if ( geometry::intersects(areal1, areal2) )
if ( geometry::intersects(areal1, areal2, strategies) )
{
return 0;
return return_type(0);
}
return linear_to_linear
<
Areal1, Areal2, Strategy
>::apply(areal1, areal2, strategy, false);
Areal1, Areal2, Strategies
>::apply(areal1, areal2, strategies, false);
}
};
@@ -99,7 +91,7 @@ template <typename Linear, typename Areal, typename Strategy>
struct distance
<
Linear, Areal, Strategy,
linear_tag, areal_tag,
linear_tag, areal_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::linear_to_areal
@@ -112,7 +104,7 @@ template <typename Areal, typename Linear, typename Strategy>
struct distance
<
Areal, Linear, Strategy,
areal_tag, linear_tag,
areal_tag, linear_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::linear_to_areal
@@ -126,7 +118,7 @@ template <typename Areal1, typename Areal2, typename Strategy>
struct distance
<
Areal1, Areal2, Strategy,
areal_tag, areal_tag,
areal_tag, areal_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::areal_to_areal

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2018, Oracle and/or its affiliates.
// Copyright (c) 2018-2021, 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
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -10,9 +11,16 @@
#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 <iterator>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/geometry/core/point_type.hpp>
namespace boost { namespace geometry
{
@@ -21,21 +29,16 @@ namespace boost { namespace geometry
namespace detail { namespace distance
{
template <typename Linear, typename Box, typename Strategy>
template <typename Linear, typename Box, typename Strategies>
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;
typedef distance::return_t<Linear, Box, Strategies> return_type;
template <typename Iterator>
static inline return_type apply(Box const& box,
Iterator begin,
Iterator end,
Strategy const& strategy)
Strategies const& strategies)
{
bool first = true;
return_type d_min(0);
@@ -44,8 +47,8 @@ struct linear_to_box
typedef typename std::iterator_traits<Iterator>::value_type
Segment;
return_type d = dispatch::distance<Segment, Box, Strategy>
::apply(*it, box, strategy);
return_type d = dispatch::distance<Segment, Box, Strategies>
::apply(*it, box, strategies);
if ( first || d < d_min )
{
@@ -57,25 +60,25 @@ struct linear_to_box
static inline return_type apply(Linear const& linear,
Box const& box,
Strategy const& strategy)
Strategies const& strategies)
{
if ( geometry::intersects(linear, box) )
{
return 0;
return return_type(0);
}
return apply(box,
geometry::segments_begin(linear),
geometry::segments_end(linear),
strategy);
strategies);
}
static inline return_type apply(Box const& box,
Linear const& linear,
Strategy const& strategy)
Strategies const& strategies)
{
return apply(linear, box, strategy);
return apply(linear, box, strategies);
}
};

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -10,19 +11,18 @@
#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/algorithms/detail/distance/range_to_geometry_rtree.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/num_segments.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/core/point_type.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>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
@@ -33,19 +33,14 @@ namespace detail { namespace distance
{
template <typename Linear1, typename Linear2, typename Strategy>
template <typename Linear1, typename Linear2, typename Strategies>
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;
typedef distance::return_t<Linear1, Linear2, Strategies> return_type;
static inline return_type apply(Linear1 const& linear1,
Linear2 const& linear2,
Strategy const& strategy,
Strategies const& strategies,
bool = false)
{
if (geometry::num_points(linear1) == 1)
@@ -54,8 +49,8 @@ struct linear_to_linear
<
typename point_type<Linear1>::type,
Linear2,
Strategy
>::apply(*points_begin(linear1), linear2, strategy);
Strategies
>::apply(*points_begin(linear1), linear2, strategies);
}
if (geometry::num_points(linear2) == 1)
@@ -64,8 +59,8 @@ struct linear_to_linear
<
typename point_type<Linear2>::type,
Linear1,
Strategy
>::apply(*points_begin(linear2), linear1, strategy);
Strategies
>::apply(*points_begin(linear2), linear1, strategies);
}
if (geometry::num_segments(linear2) < geometry::num_segments(linear1))
@@ -74,11 +69,11 @@ struct linear_to_linear
<
geometry::segment_iterator<Linear2 const>,
Linear1,
Strategy
Strategies
>::apply(geometry::segments_begin(linear2),
geometry::segments_end(linear2),
linear1,
strategy);
strategies);
}
@@ -86,11 +81,11 @@ struct linear_to_linear
<
geometry::segment_iterator<Linear1 const>,
Linear2,
Strategy
Strategies
>::apply(geometry::segments_begin(linear1),
geometry::segments_end(linear1),
linear2,
strategy);
strategies);
}
};
@@ -103,12 +98,12 @@ struct linear_to_linear
namespace dispatch
{
template <typename Linear1, typename Linear2, typename Strategy>
template <typename Linear1, typename Linear2, typename Strategy, typename StrategyTag>
struct distance
<
Linear1, Linear2, Strategy,
linear_tag, linear_tag,
strategy_tag_distance_point_segment, false
linear_tag, linear_tag,
StrategyTag, false
> : detail::distance::linear_to_linear
<
Linear1, Linear2, Strategy

View File

@@ -1,8 +1,10 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -10,7 +12,14 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
#include <boost/range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/distance/range_to_geometry_rtree.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
@@ -18,13 +27,6 @@
#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
{
@@ -34,139 +36,118 @@ namespace detail { namespace distance
{
template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
template <typename MultiPoint1, typename MultiPoint2, typename Strategies>
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;
typedef distance::return_t<MultiPoint1, MultiPoint2, Strategies> return_type;
static inline return_type apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
Strategy const& strategy)
Strategies const& strategies)
{
if (boost::size(multipoint2) < boost::size(multipoint1))
{
return point_or_segment_range_to_geometry_rtree
<
typename boost::range_iterator<MultiPoint2 const>::type,
MultiPoint1,
Strategy
Strategies
>::apply(boost::begin(multipoint2),
boost::end(multipoint2),
multipoint1,
strategy);
strategies);
}
return point_or_segment_range_to_geometry_rtree
<
typename boost::range_iterator<MultiPoint1 const>::type,
MultiPoint2,
Strategy
Strategies
>::apply(boost::begin(multipoint1),
boost::end(multipoint1),
multipoint2,
strategy);
strategies);
}
};
template <typename MultiPoint, typename Linear, typename Strategy>
template <typename MultiPoint, typename Linear, typename Strategies>
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)
static inline auto apply(MultiPoint const& multipoint,
Linear const& linear,
Strategies const& strategies)
{
return detail::distance::point_or_segment_range_to_geometry_rtree
<
typename boost::range_iterator<MultiPoint const>::type,
Linear,
Strategy
Strategies
>::apply(boost::begin(multipoint),
boost::end(multipoint),
linear,
strategy);
strategies);
}
static inline return_type apply(Linear const& linear,
MultiPoint const& multipoint,
Strategy const& strategy)
static inline auto apply(Linear const& linear,
MultiPoint const& multipoint,
Strategies const& strategies)
{
return apply(multipoint, linear, strategy);
return apply(multipoint, linear, strategies);
}
};
template <typename MultiPoint, typename Areal, typename Strategy>
template <typename MultiPoint, typename Areal, typename Strategies>
class multipoint_to_areal
{
private:
struct not_covered_by_areal
struct covered_by_areal
{
not_covered_by_areal(Areal const& areal)
: m_areal(areal)
covered_by_areal(Areal const& areal, Strategies const& strategy)
: m_areal(areal), m_strategy(strategy)
{}
template <typename Point>
inline bool apply(Point const& point) const
inline bool operator()(Point const& point) const
{
return !geometry::covered_by(point, m_areal);
return geometry::covered_by(point, m_areal, m_strategy);
}
Areal const& m_areal;
Strategies 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;
typedef distance::return_t<MultiPoint, Areal, Strategies> return_type;
static inline return_type apply(MultiPoint const& multipoint,
Areal const& areal,
Strategy const& strategy)
Strategies const& strategies)
{
not_covered_by_areal predicate(areal);
covered_by_areal predicate(areal, strategies);
if (check_iterator_range
<
not_covered_by_areal, false
>::apply(boost::begin(multipoint),
boost::end(multipoint),
predicate))
if (! boost::empty(multipoint) &&
std::none_of(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
Strategies
>::apply(boost::begin(multipoint),
boost::end(multipoint),
areal,
strategy);
strategies);
}
return 0;
return return_type(0);
}
static inline return_type apply(Areal const& areal,
MultiPoint const& multipoint,
Strategy const& strategy)
Strategies const& strategies)
{
return apply(multipoint, areal, strategy);
return apply(multipoint, areal, strategies);
}
};

View File

@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2019.
// Modifications copyright (c) 2014-2019, Oracle and/or its affiliates.
// This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2021, 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
@@ -22,10 +22,22 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
#include <iterator>
#include <type_traits>
#include <boost/core/ignore_unused.hpp>
#include <boost/range.hpp>
#include <boost/type_traits/is_same.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/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/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_type.hpp>
@@ -34,20 +46,11 @@
#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/relate/services.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>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
@@ -58,12 +61,28 @@ namespace detail { namespace distance
{
template <typename P1, typename P2, typename Strategy>
template
<
typename P1, typename P2, typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
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)
auto apply(P1 const& p1, P2 const& p2, Strategies const& strategies)
{
boost::ignore_unused(strategies);
return strategies.distance(p1, p2).apply(p1, p2);
}
};
// TEMP?
// called by geometry_to_range
template <typename P1, typename P2, typename Strategy>
struct point_to_point<P1, P2, Strategy, false>
{
static inline
auto apply(P1 const& p1, P2 const& p2, Strategy const& strategy)
{
boost::ignore_unused(strategy);
return strategy.apply(p1, p2);
@@ -71,52 +90,101 @@ struct point_to_point
};
template
<
typename Point, typename Segment, typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct point_to_segment
{
static inline auto apply(Point const& point, Segment const& segment,
Strategies const& strategies)
{
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(strategies);
return strategies.distance(point, segment).apply(point, p[0], p[1]);
}
};
// TEMP?
// called by geometry_to_range
template <typename Point, typename Segment, typename Strategy>
struct point_to_segment<Point, Segment, Strategy, false>
{
static inline auto 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 Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct point_to_box
{
static inline auto apply(Point const& point, Box const& box,
Strategies const& strategies)
{
boost::ignore_unused(strategies);
return strategies.distance(point, box).apply(point, box);
}
};
// TEMP?
// called by geometry_to_range
template <typename Point, typename Box, typename Strategy>
struct point_to_box<Point, Box, Strategy, false>
{
static inline auto apply(Point const& point, Box const& box,
Strategy const& strategy)
{
boost::ignore_unused(strategy);
return strategy.apply(point, box);
}
};
template
<
typename Point,
typename Range,
closure_selector Closure,
typename Strategy
typename Strategies
>
class point_to_range
{
private:
typedef typename strategy::distance::services::comparable_type
<
Strategy
>::type comparable_strategy;
typedef distance::strategy_t<Point, Range, Strategies> strategy_type;
typedef detail::closest_feature::point_to_point_range
<
Point, Range, Closure, comparable_strategy
Point, Range, Closure
> point_to_point_range;
public:
typedef typename strategy::distance::services::return_type
<
Strategy,
Point,
typename boost::range_value<Range>::type
>::type return_type;
typedef distance::return_t<Point, Range, Strategies> return_type;
static inline return_type apply(Point const& point, Range const& range,
Strategy const& strategy)
Strategies const& strategies)
{
return_type const zero = return_type(0);
if (boost::size(range) == 0)
{
return zero;
return return_type(0);
}
namespace sds = strategy::distance::services;
typename sds::return_type
<
comparable_strategy,
Point,
typename point_type<Range>::type
>::type cd_min;
distance::creturn_t<Point, Range, Strategies> cd_min;
std::pair
<
@@ -126,18 +194,18 @@ public:
= point_to_point_range::apply(point,
boost::begin(range),
boost::end(range),
sds::get_comparable
strategy::distance::services::get_comparable
<
Strategy
>::apply(strategy),
strategy_type
>::apply(strategies.distance(point, range)),
cd_min);
return
is_comparable<Strategy>::value
is_comparable<strategy_type>::value
?
cd_min
:
strategy.apply(point, *it_pair.first, *it_pair.second);
strategies.distance(point, range).apply(point, *it_pair.first, *it_pair.second);
}
};
@@ -147,29 +215,25 @@ template
typename Point,
typename Ring,
closure_selector Closure,
typename Strategy
typename Strategies
>
struct point_to_ring
{
typedef typename strategy::distance::services::return_type
<
Strategy, Point, typename point_type<Ring>::type
>::type return_type;
typedef distance::return_t<Point, Ring, Strategies> return_type;
static inline return_type apply(Point const& point,
Ring const& ring,
Strategy const& strategy)
Strategies const& strategies)
{
// TODO: pass strategy
if (within::within_point_geometry(point, ring))
if (within::within_point_geometry(point, ring, strategies))
{
return return_type(0);
}
return point_to_range
<
Point, Ring, closure<Ring>::value, Strategy
>::apply(point, ring, strategy);
Point, Ring, closure<Ring>::value, Strategies
>::apply(point, ring, strategies);
}
};
@@ -179,20 +243,17 @@ template
typename Point,
typename Polygon,
closure_selector Closure,
typename Strategy
typename Strategies
>
class point_to_polygon
{
public:
typedef typename strategy::distance::services::return_type
<
Strategy, Point, typename point_type<Polygon>::type
>::type return_type;
typedef distance::return_t<Point, Polygon, Strategies> return_type;
private:
typedef point_to_range
<
Point, typename ring_type<Polygon>::type, Closure, Strategy
Point, typename ring_type<Polygon>::type, Closure, Strategies
> per_ring;
struct distance_to_interior_rings
@@ -201,31 +262,29 @@ private:
static inline return_type apply(Point const& point,
InteriorRingIterator first,
InteriorRingIterator last,
Strategy const& strategy)
Strategies const& strategies)
{
for (InteriorRingIterator it = first; it != last; ++it)
{
// TODO: pass strategy
if (within::within_point_geometry(point, *it))
if (within::within_point_geometry(point, *it, strategies))
{
// 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 per_ring::apply(point, *it, strategies);
}
}
return 0;
return return_type(0);
}
template <typename InteriorRings>
static inline return_type apply(Point const& point,
InteriorRings const& interior_rings,
Strategy const& strategy)
static inline return_type apply(Point const& point, InteriorRings const& interior_rings,
Strategies const& strategies)
{
return apply(point,
boost::begin(interior_rings),
boost::end(interior_rings),
strategy);
strategies);
}
};
@@ -233,20 +292,20 @@ private:
public:
static inline return_type apply(Point const& point,
Polygon const& polygon,
Strategy const& strategy)
Strategies const& strategies)
{
// TODO: pass strategy
if (! within::covered_by_point_geometry(point, exterior_ring(polygon)))
if (! within::covered_by_point_geometry(point, exterior_ring(polygon),
strategies))
{
// 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);
return per_ring::apply(point, exterior_ring(polygon), strategies);
}
// Check interior rings
return distance_to_interior_rings::apply(point,
interior_rings(polygon),
strategy);
strategies);
}
};
@@ -255,8 +314,8 @@ template
<
typename Point,
typename MultiGeometry,
typename Strategy,
bool CheckCoveredBy = boost::is_same
typename Strategies,
bool CheckCoveredBy = std::is_same
<
typename tag<MultiGeometry>::type, multi_polygon_tag
>::value
@@ -266,41 +325,35 @@ class point_to_multigeometry
private:
typedef detail::closest_feature::geometry_to_range geometry_to_range;
typedef distance::strategy_t<Point, MultiGeometry, Strategies> strategy_type;
public:
typedef typename strategy::distance::services::return_type
<
Strategy,
Point,
typename point_type<MultiGeometry>::type
>::type return_type;
typedef distance::return_t<Point, MultiGeometry, Strategies> return_type;
static inline return_type apply(Point const& point,
MultiGeometry const& multigeometry,
Strategy const& strategy)
Strategies const& strategies)
{
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;
distance::creturn_t<Point, MultiGeometry, Strategies> 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::distance::services::get_comparable
<
Strategy
>::apply(strategy),
strategy_type
>::apply(strategies.distance(point, multigeometry)),
cd);
// TODO - It would be possible to use a tool similar to result_from_distance
// but working in the opposite way, i.e. calculating the distance
// value from comparable distance value. This way the additional distance
// call would not be needed.
return
is_comparable<Strategy>::value
is_comparable<strategy_type>::value
?
cd
:
@@ -311,38 +364,32 @@ public:
<
typename selector_type::iterator_type
>::value_type,
Strategy
>::apply(point, *it_min, strategy);
Strategies
>::apply(point, *it_min, strategies);
}
};
// 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>
template <typename Point, typename MultiPolygon, typename Strategies>
struct point_to_multigeometry<Point, MultiPolygon, Strategies, true>
{
typedef typename strategy::distance::services::return_type
<
Strategy,
Point,
typename point_type<MultiPolygon>::type
>::type return_type;
typedef distance::return_t<Point, MultiPolygon, Strategies> return_type;
static inline return_type apply(Point const& point,
MultiPolygon const& multipolygon,
Strategy const& strategy)
Strategies const& strategies)
{
// TODO: pass strategy
if (within::covered_by_point_geometry(point, multipolygon))
if (within::covered_by_point_geometry(point, multipolygon, strategies))
{
return 0;
return return_type(0);
}
return point_to_multigeometry
<
Point, MultiPolygon, Strategy, false
>::apply(point, multipolygon, strategy);
Point, MultiPolygon, Strategies, false
>::apply(point, multipolygon, strategies);
}
};
@@ -358,7 +405,6 @@ namespace dispatch
{
// Point-point
template <typename P1, typename P2, typename Strategy>
struct distance
<
@@ -368,7 +414,6 @@ struct distance
{};
// Point-line version 2, where point-segment strategy is specified
template <typename Point, typename Linestring, typename Strategy>
struct distance
<
@@ -378,7 +423,6 @@ struct distance
{};
// Point-ring , where point-segment strategy is specified
template <typename Point, typename Ring, typename Strategy>
struct distance
<
@@ -391,7 +435,6 @@ struct distance
{};
// Point-polygon , where point-segment strategy is specified
template <typename Point, typename Polygon, typename Strategy>
struct distance
<
@@ -404,29 +447,13 @@ struct distance
{};
// 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]);
}
};
> : detail::distance::point_to_segment<Point, Segment, Strategy>
{};
template <typename Point, typename Box, typename Strategy>
@@ -434,18 +461,8 @@ 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);
}
};
> : detail::distance::point_to_box<Point, Box, Strategy>
{};
template<typename Point, typename MultiPoint, typename Strategy>

View File

@@ -1,8 +1,8 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Boost.Geometry
// Copyright (c) 2014-2021, 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
@@ -13,18 +13,18 @@
#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>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/iterators/detail/has_one_element.hpp>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
@@ -40,7 +40,7 @@ template
<
typename PointOrSegmentIterator,
typename Geometry,
typename Strategy
typename Strategies
>
class point_or_segment_range_to_geometry_rtree
{
@@ -54,37 +54,27 @@ private:
typedef detail::closest_feature::range_to_range_rtree range_to_range;
typedef distance::strategy_t<point_or_segment_type, Geometry, Strategies> strategy_type;
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;
typedef distance::return_t<point_or_segment_type, Geometry, Strategies> return_type;
static inline return_type apply(PointOrSegmentIterator first,
PointOrSegmentIterator last,
Geometry const& geometry,
Strategy const& strategy)
Strategies const& strategies)
{
namespace sds = strategy::distance::services;
BOOST_GEOMETRY_ASSERT( first != last );
if ( geometry::has_one_element(first, last) )
if ( detail::has_one_element(first, last) )
{
return dispatch::distance
<
point_or_segment_type, Geometry, Strategy
>::apply(*first, geometry, strategy);
point_or_segment_type, Geometry, Strategies
>::apply(*first, geometry, strategies);
}
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;
distance::creturn_t<point_or_segment_type, Geometry, Strategies> cd_min;
std::pair
<
@@ -95,28 +85,25 @@ public:
last,
selector_type::begin(geometry),
selector_type::end(geometry),
sds::get_comparable
<
Strategy
>::apply(strategy),
strategies,
cd_min);
return
is_comparable<Strategy>::value
is_comparable<strategy_type>::value
?
cd_min
:
dispatch::distance
<
point_or_segment_type,
point_or_segment_type,
typename std::iterator_traits
<
typename selector_type::iterator_type
>::value_type,
Strategy
Strategies
>::apply(closest_features.first,
*closest_features.second,
strategy);
strategies);
}
};

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2019 Oracle and/or its affiliates.
// Copyright (c) 2014-2023 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
@@ -13,14 +13,23 @@
#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/mpl/if.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/type_traits/is_same.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/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/detail/dummy_geometries.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/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -29,16 +38,6 @@
#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>
@@ -50,7 +49,6 @@
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
@@ -60,26 +58,24 @@ namespace detail { namespace distance
{
// TODO: Take strategy
template <typename Segment, typename Box>
inline bool intersects_segment_box(Segment const& segment, Box const& box)
template <typename Segment, typename Box, typename Strategy>
inline bool intersects_segment_box(Segment const& segment, Box const& box,
Strategy const& strategy)
{
typedef typename strategy::disjoint::services::default_strategy
<
Segment, Box
>::type strategy_type;
return ! detail::disjoint::disjoint_segment_box::apply(segment, box,
strategy_type());
return ! detail::disjoint::disjoint_segment_box::apply(segment, box, strategy);
}
// TODO: segment_to_box_2D_generic is not used anymore. Remove?
// TODO: Furthermore this utility can potentially use different strategy than
// the one that was passed into bg::distance() but it seems this is by design.
template
<
typename Segment,
typename Box,
typename Strategy,
bool UsePointBoxStrategy = false
typename Strategies,
bool UsePointBoxStrategy = false // use only PointSegment strategy
>
class segment_to_box_2D_generic
{
@@ -87,46 +83,29 @@ 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 distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type;
typedef detail::closest_feature::point_to_point_range
<
segment_point,
std::vector<box_point>,
open,
comparable_strategy
open
> 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;
// TODO: Or should the return type be defined by sb_strategy_type?
typedef distance::return_t<box_point, Segment, Strategies> return_type;
static inline return_type apply(Segment const& segment,
Box const& box,
Strategy const& strategy,
Strategies const& strategies,
bool check_intersection = true)
{
if (check_intersection && intersects_segment_box(segment, box))
if (check_intersection && intersects_segment_box(segment, box, strategies))
{
return 0;
return return_type(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]);
@@ -135,8 +114,15 @@ public:
// get box points
std::vector<box_point> box_points(4);
detail::assign_box_corners_oriented<true>(box, box_points);
comparable_return_type cd[6];
ps_strategy_type const strategy = strategies.distance(dummy_point(), dummy_segment());
auto const cstrategy = strategy::distance::services::get_comparable
<
ps_strategy_type
>::apply(strategy);
distance::creturn_t<box_point, Segment, Strategies> cd[6];
for (unsigned int i = 0; i < 4; ++i)
{
cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
@@ -168,19 +154,19 @@ public:
}
}
if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
if (BOOST_GEOMETRY_CONDITION(is_comparable<ps_strategy_type>::value))
{
return cd[imin];
}
if (imin < 4)
{
return strategy.get_distance_ps_strategy().apply(box_points[imin], p[0], p[1]);
return strategy.apply(box_points[imin], p[0], p[1]);
}
else
{
unsigned int bimin = imin - 4;
return strategy.get_distance_ps_strategy().apply(p[bimin],
return strategy.apply(p[bimin],
*bit_min[bimin].first,
*bit_min[bimin].second);
}
@@ -192,57 +178,31 @@ template
<
typename Segment,
typename Box,
typename Strategy
typename Strategies
>
class segment_to_box_2D_generic<Segment, Box, Strategy, true>
class segment_to_box_2D_generic<Segment, Box, Strategies, true> // Use both PointSegment and PointBox strategies
{
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;
typedef distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type;
typedef distance::strategy_t<segment_point, Box, Strategies> pb_strategy_type;
public:
typedef typename strategy::distance::services::return_type
<
Strategy, segment_point, box_point
>::type return_type;
// TODO: Or should the return type be defined by sb_strategy_type?
typedef distance::return_t<box_point, Segment, Strategies> return_type;
static inline return_type apply(Segment const& segment,
Box const& box,
Strategy const& strategy,
Strategies const& strategies,
bool check_intersection = true)
{
if (check_intersection && intersects_segment_box(segment, box))
if (check_intersection && intersects_segment_box(segment, box, strategies))
{
return 0;
return return_type(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]);
@@ -251,15 +211,28 @@ public:
// get box points
std::vector<box_point> box_points(4);
detail::assign_box_corners_oriented<true>(box, box_points);
comparable_return_type cd[6];
distance::creturn_t<box_point, Segment, Strategies> cd[6];
ps_strategy_type ps_strategy = strategies.distance(dummy_point(), dummy_segment());
auto const ps_cstrategy = strategy::distance::services::get_comparable
<
ps_strategy_type
>::apply(ps_strategy);
boost::ignore_unused(ps_strategy, ps_cstrategy);
for (unsigned int i = 0; i < 4; ++i)
{
cd[i] = cstrategy.apply(box_points[i], p[0], p[1]);
cd[i] = ps_cstrategy.apply(box_points[i], p[0], p[1]);
}
point_box_comparable_strategy pb_cstrategy;
boost::ignore_unused(pb_cstrategy);
pb_strategy_type const pb_strategy = strategies.distance(dummy_point(), dummy_box());
auto const pb_cstrategy = strategy::distance::services::get_comparable
<
pb_strategy_type
>::apply(pb_strategy);
boost::ignore_unused(pb_strategy, pb_cstrategy);
cd[4] = pb_cstrategy.apply(p[0], box);
cd[5] = pb_cstrategy.apply(p[1], box);
@@ -272,18 +245,23 @@ public:
}
}
if (is_comparable<Strategy>::value)
{
return cd[imin];
}
if (imin < 4)
{
strategy.apply(box_points[imin], p[0], p[1]);
if (is_comparable<ps_strategy_type>::value)
{
return cd[imin];
}
return ps_strategy.apply(box_points[imin], p[0], p[1]);
}
else
{
return point_box_strategy().apply(p[imin - 4], box);
if (is_comparable<pb_strategy_type>::value)
{
return cd[imin];
}
return pb_strategy.apply(p[imin - 4], box);
}
}
};
@@ -296,7 +274,7 @@ template
typename ReturnType,
typename SegmentPoint,
typename BoxPoint,
typename SBStrategy
typename Strategies
>
class segment_to_box_2D
{
@@ -355,10 +333,8 @@ private:
SegmentPoint const& p1,
BoxPoint const& bottom_right,
BoxPoint const& top_right,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
boost::ignore_unused(sb_strategy);
// the implementation below is written for non-negative slope
// segments
//
@@ -369,8 +345,7 @@ private:
LessEqual less_equal;
typename SBStrategy::distance_ps_strategy::type ps_strategy =
sb_strategy.get_distance_ps_strategy();
auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
if (less_equal(geometry::get<1>(bottom_right), geometry::get<1>(p0)))
{
@@ -412,19 +387,19 @@ private:
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
boost::ignore_unused(sb_strategy);
return apply(p0, p1, p0, top_left, sb_strategy);
return apply(p0, p1, p0, top_left, strategies);
}
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
SegmentPoint const& p_max,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
boost::ignore_unused(sb_strategy);
auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
typedef cast_to_result<ReturnType> cast;
LessEqual less_equal;
@@ -432,22 +407,21 @@ private:
// 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(
ReturnType diff = 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));
std::remove_const_t<decltype(ps_strategy)>,
SegmentPoint, BoxPoint
>::apply(ps_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));
return cast::apply(ps_strategy.apply(top_left, p0, p1));
}
};
@@ -460,7 +434,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
SBStrategy const& sb_strategy,
Strategies const& strategies,
ReturnType& result)
{
// p0 lies to the right of the box
@@ -470,7 +444,7 @@ private:
<
LessEqual
>::apply(p0, p1, bottom_right, top_right,
sb_strategy);
strategies);
return true;
}
@@ -481,7 +455,7 @@ private:
<
typename other_compare<LessEqual>::type
>::apply(p1, p0, top_left, bottom_left,
sb_strategy);
strategies);
return true;
}
@@ -498,7 +472,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
SBStrategy const& sb_strategy,
Strategies const& strategies,
ReturnType& result)
{
typedef compare_less_equal<ReturnType, false> GreaterEqual;
@@ -506,13 +480,20 @@ private:
// the segment lies below the box
if (geometry::get<1>(p1) < geometry::get<1>(bottom_left))
{
auto const sb_strategy = strategies.distance(dummy_segment(), dummy_box());
// TODO: this strategy calls this algorithm's again, specifically:
// geometry::detail::distance::segment_to_box_2D<>::call_above_of_box
// If possible rewrite them to avoid this.
// For now just pass umbrella strategy.
result = sb_strategy.template segment_below_of_box
<
LessEqual,
ReturnType
>(p0, p1,
top_left, top_right,
bottom_left, bottom_right);
bottom_left, bottom_right,
strategies);
return true;
}
@@ -522,11 +503,11 @@ private:
result = (std::min)(above_of_box
<
LessEqual
>::apply(p0, p1, top_left, sb_strategy),
>::apply(p0, p1, top_left, strategies),
above_of_box
<
GreaterEqual
>::apply(p1, p0, top_right, sb_strategy));
>::apply(p1, p0, top_right, strategies));
return true;
}
return false;
@@ -539,28 +520,23 @@ private:
SegmentPoint const& p1,
BoxPoint const& corner1,
BoxPoint const& corner2,
SBStrategy const& sb_strategy,
Strategies const& strategies,
ReturnType& result)
{
typedef typename geometry::strategy::side::services::default_strategy
<
typename geometry::cs_tag<SegmentPoint>::type
>::type side;
auto const side_strategy = strategies.side();
auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
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::apply(p0, p1, corner1) * sign < 0)
if (side_strategy.apply(p0, p1, corner1) * sign < 0)
{
result = cast::apply(ps_strategy.apply(corner1, p0, p1));
return true;
}
if (side::apply(p0, p1, corner2) * sign > 0)
if (side_strategy.apply(p0, p1, corner2) * sign > 0)
{
result = cast::apply(ps_strategy.apply(corner2, p0, p1));
return true;
@@ -576,7 +552,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
typedef compare_less_equal<ReturnType, true> less_equal;
@@ -596,7 +572,7 @@ private:
less_equal
>::apply(p0, p1,
top_left, top_right, bottom_left, bottom_right,
sb_strategy, result))
strategies, result))
{
return result;
}
@@ -606,14 +582,14 @@ private:
less_equal
>::apply(p0, p1,
top_left, top_right, bottom_left, bottom_right,
sb_strategy, result))
strategies, result))
{
return result;
}
if (check_generic_position::apply(p0, p1,
top_left, bottom_right,
sb_strategy, result))
strategies, result))
{
return result;
}
@@ -630,7 +606,7 @@ private:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
typedef compare_less_equal<ReturnType, false> greater_equal;
@@ -647,7 +623,7 @@ private:
greater_equal
>::apply(p0, p1,
bottom_left, bottom_right, top_left, top_right,
sb_strategy, result))
strategies, result))
{
return result;
}
@@ -657,14 +633,14 @@ private:
greater_equal
>::apply(p1, p0,
top_right, top_left, bottom_right, bottom_left,
sb_strategy, result))
strategies, result))
{
return result;
}
if (check_generic_position::apply(p0, p1,
bottom_left, top_right,
sb_strategy, result))
strategies, result))
{
return result;
}
@@ -680,9 +656,9 @@ public:
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
BOOST_GEOMETRY_ASSERT( geometry::less<SegmentPoint>()(p0, p1)
BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, Strategies>()(p0, p1))
|| geometry::has_nan_coordinate(p0)
|| geometry::has_nan_coordinate(p1) );
@@ -692,13 +668,13 @@ public:
return negative_slope_segment(p0, p1,
top_left, top_right,
bottom_left, bottom_right,
sb_strategy);
strategies);
}
return non_negative_slope_segment(p0, p1,
top_left, top_right,
bottom_left, bottom_right,
sb_strategy);
strategies);
}
template <typename LessEqual>
@@ -706,18 +682,18 @@ public:
SegmentPoint const& p1,
SegmentPoint const& p_max,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
return above_of_box<LessEqual>::apply(p0, p1, p_max, top_left, sb_strategy);
return above_of_box<LessEqual>::apply(p0, p1, p_max, top_left, strategies);
}
template <typename LessEqual>
static inline ReturnType call_above_of_box(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
return above_of_box<LessEqual>::apply(p0, p1, top_left, sb_strategy);
return above_of_box<LessEqual>::apply(p0, p1, top_left, strategies);
}
};
@@ -728,7 +704,7 @@ template
typename Segment,
typename Box,
typename std::size_t Dimension,
typename SBStrategy
typename Strategies
>
class segment_to_box
: not_implemented<Segment, Box>
@@ -739,87 +715,56 @@ template
<
typename Segment,
typename Box,
typename SBStrategy
typename Strategies
>
class segment_to_box<Segment, Box, 2, SBStrategy>
class segment_to_box<Segment, Box, 2, Strategies>
{
private:
typedef typename point_type<Segment>::type segment_point;
typedef typename point_type<Box>::type box_point;
typedef distance::strategy_t<Segment, Box, Strategies> strategy_type;
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;
typedef distance::return_t<Segment, Box, Strategies> return_type;
static inline return_type apply(Segment const& segment,
Box const& box,
SBStrategy const& sb_strategy)
Strategies const& strategies)
{
typedef typename point_type<Segment>::type segment_point;
typedef typename point_type<Box>::type box_point;
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()))
if (detail::equals::equals_point_point(p[0], p[1], strategies))
{
typedef typename boost::mpl::if_
<
boost::is_same
<
ps_comparable_strategy,
SBStrategy
>,
typename strategy::distance::services::comparable_type
<
typename detail::distance::default_strategy
<
segment_point, Box
>::type
>::type,
typename detail::distance::default_strategy
<
segment_point, Box
>::type
>::type point_box_strategy_type;
return dispatch::distance
<
segment_point,
Box,
point_box_strategy_type
>::apply(p[0], box, point_box_strategy_type());
Strategies
>::apply(p[0], box, strategies);
}
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);
strategy_type::mirror(p[0], p[1],
bottom_left, bottom_right,
top_left, top_right);
if (geometry::less<segment_point>()(p[0], p[1]))
typedef geometry::less<segment_point, -1, Strategies> less_type;
if (less_type()(p[0], p[1]))
{
return segment_to_box_2D
<
return_type,
segment_point,
box_point,
SBStrategy
Strategies
>::apply(p[0], p[1],
top_left, top_right, bottom_left, bottom_right,
sb_strategy);
strategies);
}
else
{
@@ -828,10 +773,10 @@ public:
return_type,
segment_point,
box_point,
SBStrategy
Strategies
>::apply(p[1], p[0],
top_left, top_right, bottom_left, bottom_right,
sb_strategy);
strategies);
}
}
};
@@ -846,24 +791,15 @@ namespace dispatch
{
template <typename Segment, typename Box, typename Strategy>
template <typename Segment, typename Box, typename Strategies>
struct distance
<
Segment, Box, Strategy, segment_tag, box_tag,
Segment, Box, Strategies, 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)
static inline auto apply(Segment const& segment, Box const& box,
Strategies const& strategies)
{
assert_dimension_equal<Segment, Box>();
@@ -872,8 +808,8 @@ struct distance
Segment,
Box,
dimension<Segment>::value,
Strategy
>::apply(segment, box, strategy);
Strategies
>::apply(segment, box, strategies);
}
};

View File

@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Copyright (c) 2014-2021, 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
@@ -15,20 +16,19 @@
#include <boost/core/addressof.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/detail/distance/is_comparable.hpp>
#include <boost/geometry/algorithms/detail/distance/strategy_utils.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/algorithms/intersects.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>
#include <boost/geometry/util/condition.hpp>
namespace boost { namespace geometry
@@ -42,35 +42,18 @@ namespace detail { namespace distance
// compute segment-segment distance
template<typename Segment1, typename Segment2, typename Strategy>
template<typename Segment1, typename Segment2, typename Strategies>
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;
typedef distance::strategy_t<Segment1, Segment2, Strategies> strategy_type;
public:
typedef typename strategy::distance::services::return_type
<
Strategy,
typename point_type<Segment1>::type,
typename point_type<Segment2>::type
>::type return_type;
typedef distance::return_t<Segment1, Segment2, Strategies> return_type;
static inline return_type
apply(Segment1 const& segment1, Segment2 const& segment2,
Strategy const& strategy)
static inline return_type apply(Segment1 const& segment1, Segment2 const& segment2,
Strategies const& strategies)
{
if (geometry::intersects(segment1, segment2))
if (geometry::intersects(segment1, segment2, strategies))
{
return 0;
}
@@ -83,13 +66,14 @@ public:
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);
strategy_type const strategy = strategies.distance(segment1, segment2);
comparable_return_type d[4];
auto const cstrategy = strategy::distance::services::get_comparable
<
strategy_type
>::apply(strategy);
distance::creturn_t<Segment1, Segment2, Strategies> 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]);
@@ -98,7 +82,7 @@ public:
std::size_t imin = std::distance(boost::addressof(d[0]),
std::min_element(d, d + 4));
if (BOOST_GEOMETRY_CONDITION(is_comparable<Strategy>::value))
if (BOOST_GEOMETRY_CONDITION(is_comparable<strategy_type>::value))
{
return d[imin];
}

View File

@@ -0,0 +1,64 @@
// Boost.Geometry
// Copyright (c) 2021, 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_ALGORITHS_DETAIL_DISTANCE_STRATEGY_UTILS_HPP
#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_STRATEGY_UTILS_HPP
#include <utility>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Geometry1, typename Geometry2, typename Strategies>
using strategy_t = decltype(
std::declval<Strategies>().distance(std::declval<Geometry1>(), std::declval<Geometry2>()));
template <typename Geometry1, typename Geometry2, typename Strategies>
using return_t = typename strategy::distance::services::return_type
<
strategy_t<Geometry1, Geometry2, Strategies>,
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type
>::type;
template <typename Geometry1, typename Geometry2, typename Strategies>
using cstrategy_t = typename strategy::distance::services::comparable_type
<
strategy_t<Geometry1, Geometry2, Strategies>
>::type;
template <typename Geometry1, typename Geometry2, typename Strategies>
using creturn_t = typename strategy::distance::services::return_type
<
cstrategy_t<Geometry1, Geometry2, Strategies>,
typename point_type<Geometry1>::type,
typename point_type<Geometry2>::type
>::type;
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_STRATEGY_UTILS_HPP

View File

@@ -0,0 +1,56 @@
// Boost.Geometry
// Copyright (c) 2021, 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_DUMMY_GEOMETRIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DUMMY_GEOMETRIES_HPP
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
struct dummy_point {};
struct dummy_segment {};
struct dummy_box {};
struct dummy_linestring {};
struct dummy_ring {};
struct dummy_polygon {};
struct dummy_multi_point {};
struct dummy_multi_linestring {};
struct dummy_multi_polygon {};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
namespace traits
{
template <> struct tag<geometry::detail::dummy_point> { typedef point_tag type; };
template <> struct tag<geometry::detail::dummy_segment> { typedef segment_tag type; };
template <> struct tag<geometry::detail::dummy_box> { typedef box_tag type; };
template <> struct tag<geometry::detail::dummy_linestring> { typedef linestring_tag type; };
template <> struct tag<geometry::detail::dummy_ring> { typedef ring_tag type; };
template <> struct tag<geometry::detail::dummy_polygon> { typedef polygon_tag type; };
template <> struct tag<geometry::detail::dummy_multi_point> { typedef multi_point_tag type; };
template <> struct tag<geometry::detail::dummy_multi_linestring> { typedef multi_linestring_tag type; };
template <> struct tag<geometry::detail::dummy_multi_polygon> { typedef multi_polygon_tag type; };
} // namespace traits
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DUMMY_GEOMETRIES_HPP

View File

@@ -1,6 +1,6 @@
// Boost.Geometry
// Copyright (c) 2018 Oracle and/or its affiliates.
// Copyright (c) 2018-2021 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
@@ -22,6 +22,8 @@
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/views/reversible_view.hpp>
namespace boost { namespace geometry
{
@@ -29,6 +31,24 @@ namespace boost { namespace geometry
namespace detail { namespace envelope
{
struct envelope_hole
{
template <typename Range, typename Box, typename Strategies>
static inline void apply(Range const& range, Box& mbr, Strategies const& strategies)
{
// Reverse holes to avoid calculating the envelope for the outside
// in spherical and geographic coordinate systems
detail::clockwise_view
<
Range const,
geometry::point_order<Range>::value == counterclockwise
? clockwise : counterclockwise
> view(range);
strategies.envelope(range, mbr).apply(view, mbr);
}
};
struct envelope_polygon
{
template <typename Polygon, typename Box, typename Strategy>
@@ -39,11 +59,14 @@ struct envelope_polygon
if (geometry::is_empty(ext_ring))
{
// use dummy multi polygon to get the strategy because there is no multi ring concept
using strategy_t = decltype(strategy.envelope(detail::dummy_multi_polygon(),
detail::dummy_box()));
// if the exterior ring is empty, consider the interior rings
envelope_multi_range
<
envelope_range
>::apply(interior_rings(polygon), mbr, strategy);
envelope_hole
>::template apply<strategy_t>(interior_rings(polygon), mbr, strategy);
}
else
{

View File

@@ -4,8 +4,8 @@
// 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.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021, 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
@@ -19,11 +19,9 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_box.hpp>
#include <boost/geometry/strategies/spherical/envelope_box.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
@@ -39,9 +37,10 @@ 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& )
static inline void apply(BoxIn const& box_in, BoxOut& mbr, Strategy const& strategy)
{
Strategy::apply(box_in, mbr);
using strategy_t = decltype(strategy.envelope(box_in, mbr));
strategy_t::apply(box_in, mbr);
}
};

View File

@@ -0,0 +1,62 @@
// Boost.Geometry
// Copyright (c) 2021, 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_ENVELOPE_GEOMETRY_COLLECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP
#include <boost/geometry/algorithms/detail/visit.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Collection>
struct envelope<Collection, geometry_collection_tag>
{
template <typename Geometry, typename Box, typename Strategies>
static inline void apply(Geometry const& geometry,
Box& mbr,
Strategies const& strategies)
{
using strategy_t = decltype(strategies.envelope(geometry, mbr));
typename strategy_t::template state<Box> state;
detail::visit_breadth_first([&](auto const& g)
{
if (! geometry::is_empty(g))
{
Box b;
envelope<util::remove_cref_t<decltype(g)>>::apply(g, b, strategies);
strategy_t::apply(state, b);
}
return true;
}, geometry);
strategy_t::result(state, mbr);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_GEOMETRY_COLLECTION_HPP

View File

@@ -4,11 +4,11 @@
// 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.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021, 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.
@@ -28,6 +28,7 @@
#include <boost/geometry/algorithms/detail/envelope/areal.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/geometry_collection.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>
@@ -36,4 +37,8 @@
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/strategies/envelope/cartesian.hpp>
#include <boost/geometry/strategies/envelope/geographic.hpp>
#include <boost/geometry/strategies/envelope/spherical.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP

View File

@@ -4,8 +4,8 @@
// 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, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2021, 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
@@ -22,22 +22,22 @@
#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/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/envelope.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/envelope/services.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
namespace boost { namespace geometry
@@ -46,31 +46,49 @@ namespace boost { namespace geometry
namespace resolve_strategy
{
template <typename Geometry>
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct envelope
{
template <typename Box, typename Strategy>
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 Box>
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 strategy::envelope::services::default_strategy
typedef typename strategies::envelope::services::default_strategy
<
typename tag<Geometry>::type,
typename cs_tag<Geometry>::type,
typename select_most_precise
<
typename coordinate_type<Geometry>::type,
typename coordinate_type<Box>::type
>::type
Geometry, Box
>::type strategy_type;
dispatch::envelope<Geometry>::apply(geometry, box, strategy_type());
@@ -79,10 +97,10 @@ struct envelope
} // namespace resolve_strategy
namespace resolve_variant
namespace resolve_dynamic
{
template <typename Geometry>
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct envelope
{
template <typename Box, typename Strategy>
@@ -93,43 +111,28 @@ struct envelope
concepts::check<Geometry const>();
concepts::check<Box>();
resolve_strategy::envelope<Geometry>::apply(geometry, box, strategy);
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 Geometry>
struct envelope<Geometry, dynamic_geometry_tag>
{
template <typename Box, typename Strategy>
struct visitor: boost::static_visitor<void>
static inline void apply(Geometry const& geometry,
Box& box,
Strategy const& strategy)
{
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
traits::visit<Geometry>::apply([&](auto const& g)
{
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);
envelope<util::remove_cref_t<decltype(g)>>::apply(g, box, strategy);
}, geometry);
}
};
} // namespace resolve_variant
} // namespace resolve_dynamic
/*!
\brief \brief_calc{envelope (with strategy)}
@@ -152,7 +155,7 @@ struct envelope<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
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);
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy);
}
/*!
@@ -173,7 +176,7 @@ inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strateg
template<typename Geometry, typename Box>
inline void envelope(Geometry const& geometry, Box& mbr)
{
resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy());
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy());
}
@@ -199,7 +202,7 @@ 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);
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy);
return mbr;
}
@@ -222,7 +225,7 @@ template<typename Box, typename Geometry>
inline Box return_envelope(Geometry const& geometry)
{
Box mbr;
resolve_variant::envelope<Geometry>::apply(geometry, mbr, default_strategy());
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy());
return mbr;
}

View File

@@ -19,7 +19,7 @@
#include <boost/geometry/algorithms/detail/normalize.hpp>
namespace boost { namespace geometry
namespace boost { namespace geometry
{
namespace detail { namespace envelope
@@ -38,7 +38,7 @@ struct intersects_antimeridian
<
CoordinateType, Units
> constants;
return
math::equals(math::abs(lat1), constants::max_latitude())
||

View File

@@ -4,8 +4,8 @@
// 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, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// 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
@@ -25,11 +25,6 @@
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope.hpp>
#include <boost/geometry/strategies/spherical/envelope.hpp>
#include <boost/geometry/strategies/geographic/envelope.hpp>
namespace boost { namespace geometry
{

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015-2018, Oracle and/or its affiliates.
// 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
@@ -17,10 +17,6 @@
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_multipoint.hpp>
#include <boost/geometry/strategies/spherical/envelope_multipoint.hpp>
namespace boost { namespace geometry
{
@@ -34,9 +30,11 @@ 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& )
static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy)
{
Strategy::apply(multipoint, mbr);
// strategy.envelope(multipoint, mbr).apply(multipoint, mbr);
using strategy_t = decltype(strategy.envelope(multipoint, mbr));
strategy_t::apply(multipoint, mbr);
}
};

View File

@@ -4,8 +4,8 @@
// 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, 2017, 2018.
// Modifications copyright (c) 2015-2018, Oracle and/or its affiliates.
// 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
@@ -22,11 +22,6 @@
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
// For backward compatibility
#include <boost/geometry/strategies/cartesian/envelope_point.hpp>
#include <boost/geometry/strategies/spherical/envelope_point.hpp>
namespace boost { namespace geometry
{
@@ -38,9 +33,11 @@ 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& )
static inline void apply(Point const& point, Box& mbr, Strategy const& strategy)
{
Strategy::apply(point, mbr);
// strategy.envelope(point, mbr).apply(point, mbr);
using strategy_t = decltype(strategy.envelope(point, mbr));
strategy_t::apply(point, mbr);
}
};

Some files were not shown because too many files have changed in this diff Show More