Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+285
View File
@@ -0,0 +1,285 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014-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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
#define BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.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/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace append
{
struct append_no_action
{
template <typename Geometry, typename Point>
static inline void apply(Geometry& , Point const& ,
signed_size_type = -1, signed_size_type = 0)
{
}
};
struct to_range_point
{
template <typename Geometry, typename Point>
static inline void apply(Geometry& geometry, Point const& point,
signed_size_type = -1, signed_size_type = 0)
{
typename geometry::point_type<Geometry>::type copy;
geometry::detail::conversion::convert_point_to_point(point, copy);
traits::push_back<Geometry>::apply(geometry, copy);
}
};
struct to_range_range
{
template <typename Geometry, typename Range>
static inline void apply(Geometry& geometry, Range const& range,
signed_size_type = -1, signed_size_type = 0)
{
using point_type = typename boost::range_value<Range>::type;
auto const end = boost::end(range);
for (auto it = boost::begin(range); it != end; ++it)
{
to_range_point::apply<Geometry, point_type>(geometry, *it);
}
}
};
struct to_polygon_point
{
template <typename Polygon, typename Point>
static inline void apply(Polygon& polygon, Point const& point,
signed_size_type ring_index, signed_size_type = 0)
{
using ring_type = typename ring_type<Polygon>::type;
if (ring_index == -1)
{
auto&& ext_ring = exterior_ring(polygon);
to_range_point::apply<ring_type, Point>(ext_ring, point);
}
else if (ring_index < signed_size_type(num_interior_rings(polygon)))
{
auto&& int_rings = interior_rings(polygon);
to_range_point::apply<ring_type, Point>(range::at(int_rings, ring_index), point);
}
}
};
struct to_polygon_range
{
template <typename Polygon, typename Range>
static inline void apply(Polygon& polygon, Range const& range,
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);
to_range_range::apply<ring_type, Range>(ext_ring, range);
}
else if (ring_index < signed_size_type(num_interior_rings(polygon)))
{
interior_ring_range_type int_rings = interior_rings(polygon);
to_range_range::apply<ring_type, Range>(range::at(int_rings, ring_index), range);
}
}
};
template <typename Policy>
struct to_multigeometry
{
template <typename MultiGeometry, typename RangeOrPoint>
static inline void apply(MultiGeometry& multigeometry,
RangeOrPoint const& range_or_point,
signed_size_type ring_index, signed_size_type multi_index)
{
Policy::template apply
<
typename boost::range_value<MultiGeometry>::type,
RangeOrPoint
>(range::at(multigeometry, multi_index), range_or_point, ring_index);
}
};
}} // namespace detail::append
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace 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<Geometry, Point, linestring_tag, point_tag>
: detail::append::to_range_point
{};
template <typename Geometry, typename Point>
struct append<Geometry, Point, ring_tag, point_tag>
: detail::append::to_range_point
{};
template <typename Polygon, typename Point>
struct append<Polygon, Point, polygon_tag, point_tag>
: detail::append::to_polygon_point
{};
template <typename Geometry, typename Range, typename RangeTag>
struct append<Geometry, Range, linestring_tag, RangeTag>
: detail::append::to_range_range
{};
template <typename Geometry, typename Range, typename RangeTag>
struct append<Geometry, Range, ring_tag, RangeTag>
: detail::append::to_range_range
{};
template <typename Polygon, typename Range, typename RangeTag>
struct append<Polygon, Range, polygon_tag, RangeTag>
: detail::append::to_polygon_range
{};
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
/*!
\brief Appends one or more points to a linestring, ring, polygon, multi-geometry
\ingroup append
\tparam Geometry \tparam_geometry
\tparam RangeOrPoint Either a range or a point, fullfilling Boost.Range concept or Boost.Geometry Point Concept
\param geometry \param_geometry
\param range_or_point The point or range to add
\param ring_index The index of the ring in case of a polygon:
exterior ring (-1, the default) or interior ring index
\param multi_index The index of the geometry to which the points are appended
\qbk{[include reference/algorithms/append.qbk]}
}
*/
template <typename Geometry, typename RangeOrPoint>
inline void append(Geometry& geometry, RangeOrPoint const& range_or_point,
signed_size_type ring_index = -1, signed_size_type multi_index = 0)
{
concepts::check<Geometry>();
dispatch::append
<
Geometry, RangeOrPoint
>::apply(geometry, range_or_point, ring_index, multi_index);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_APPEND_HPP
+371
View File
@@ -0,0 +1,371 @@
// 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-2022 Adam Wulkiewicz, Lodz, Poland.
// 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
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
#define BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/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/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/views/detail/closed_clockwise_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace area
{
struct box_area
{
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 strategies.area(box).apply(box);
}
};
struct ring_area
{
template <typename Ring, typename Strategies>
static inline typename area_result<Ring, Strategies>::type
apply(Ring const& ring, Strategies const& strategies)
{
using strategy_type = decltype(strategies.area(ring));
BOOST_CONCEPT_ASSERT( (geometry::concepts::AreaStrategy<Ring, strategy_type>) );
assert_dimension<Ring, 2>();
// Ignore warning (because using static method sometimes) on strategy
boost::ignore_unused(strategies);
// An open ring has at least three points,
// A closed ring has at least four points,
// if not, there is no (zero) area
if (boost::size(ring) < detail::minimum_ring_size<Ring>::value)
{
return typename area_result<Ring, Strategies>::type();
}
detail::closed_clockwise_view<Ring const> const view(ring);
auto it = boost::begin(view);
auto const end = boost::end(view);
strategy_type const strategy = strategies.area(ring);
typename strategy_type::template state<Ring> state;
for (auto previous = it++; it != end; ++previous, ++it)
{
strategy.apply(*previous, *it, state);
}
return strategy.result(state);
}
};
}} // namespace detail::area
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry,
typename Tag = typename tag<Geometry>::type
>
struct area : detail::calculate_null
{
template <typename Strategy>
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
return calculate_null::apply
<
typename area_result<Geometry, Strategy>::type
>(geometry, strategy);
}
};
template <typename Geometry>
struct area<Geometry, box_tag> : detail::area::box_area
{};
template <typename Ring>
struct area<Ring, ring_tag>
: detail::area::ring_area
{};
template <typename Polygon>
struct area<Polygon, polygon_tag> : detail::calculate_polygon_sum
{
template <typename Strategy>
static inline typename area_result<Polygon, Strategy>::type
apply(Polygon const& polygon, Strategy const& strategy)
{
return calculate_polygon_sum::apply
<
typename area_result<Polygon, Strategy>::type,
detail::area::ring_area
>(polygon, strategy);
}
};
template <typename MultiGeometry>
struct area<MultiGeometry, multi_polygon_tag> : detail::multi_sum
{
template <typename Strategy>
static inline typename area_result<MultiGeometry, Strategy>::type
apply(MultiGeometry const& multi, Strategy const& strategy)
{
return multi_sum::apply
<
typename area_result<MultiGeometry, Strategy>::type,
area<typename boost::range_value<MultiGeometry>::type>
>(multi, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct area
{
template <typename Geometry>
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
return dispatch::area<Geometry>::apply(geometry, strategy);
}
};
template <typename Strategy>
struct area<Strategy, false>
{
template <typename Geometry>
static auto apply(Geometry const& geometry, Strategy const& strategy)
{
using strategies::area::services::strategy_converter;
return dispatch::area
<
Geometry
>::apply(geometry, strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct area<default_strategy, false>
{
template <typename Geometry>
static inline typename area_result<Geometry>::type
apply(Geometry const& geometry, default_strategy)
{
typedef typename strategies::area::services::default_strategy
<
Geometry
>::type strategy_type;
return dispatch::area<Geometry>::apply(geometry, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic
{
template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type>
struct area
{
template <typename Strategy>
static inline typename area_result<Geometry, Strategy>::type
apply(Geometry const& geometry, Strategy const& strategy)
{
return resolve_strategy::area<Strategy>::apply(geometry, strategy);
}
};
template <typename Geometry>
struct area<Geometry, dynamic_geometry_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;
traits::visit<Geometry>::apply([&](auto const& g)
{
result = area<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
}, geometry);
return result;
}
};
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
/*!
\brief \brief_calc{area}
\ingroup area
\details \details_calc{area}. \details_default_strategy
The area algorithm calculates the surface area of all geometries having a surface, namely
box, polygon, ring, multipolygon. The units are the square of the units used for the points
defining the surface. If subject geometry is defined in meters, then area is calculated
in square meters.
The area calculation can be done in all three common coordinate systems, Cartesian, Spherical
and Geographic as well.
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{area}
\qbk{[include reference/algorithms/area.qbk]}
\qbk{[heading Examples]}
\qbk{[area] [area_output]}
*/
template <typename Geometry>
inline typename area_result<Geometry>::type
area(Geometry const& geometry)
{
concepts::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
return resolve_dynamic::area<Geometry>::apply(geometry, default_strategy());
}
/*!
\brief \brief_calc{area} \brief_strategy
\ingroup area
\details \details_calc{area} \brief_strategy. \details_strategy_reasons
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Area}
\param geometry \param_geometry
\param strategy \param_strategy{area}
\return \return_calc{area}
\qbk{distinguish,with strategy}
\qbk{
[include reference/algorithms/area.qbk]
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_area_cartesian Cartesian]
\* [link geometry.reference.strategies.strategy_area_spherical Spherical]
\* [link geometry.reference.strategies.strategy_area_geographic Geographic]
[heading Example]
[area_with_strategy]
[area_with_strategy_output]
}
*/
template <typename Geometry, typename Strategy>
inline typename area_result<Geometry, Strategy>::type
area(Geometry const& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
// detail::throw_on_empty_input(geometry);
return resolve_dynamic::area<Geometry>::apply(geometry, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_AREA_HPP
+141
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
+366
View File
@@ -0,0 +1,366 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2020-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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP
#include <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/core/static_assert.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
namespace boost { namespace geometry
{
/*!
\brief Assign a range of points to a linestring, ring or polygon
\note The point-type of the range might be different from the point-type of the geometry
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Range \tparam_range_point
\param geometry \param_geometry
\param range \param_range_point
\qbk{
[heading Notes]
[note Assign automatically clears the geometry before assigning (use append if you don't want that)]
[heading Example]
[assign_points] [assign_points_output]
[heading See also]
\* [link geometry.reference.algorithms.append append]
}
*/
template <typename Geometry, typename Range>
inline void assign_points(Geometry& geometry, Range const& range)
{
concepts::check<Geometry>();
clear(geometry);
geometry::append(geometry, range, -1, 0);
}
/*!
\brief assign to a box inverse infinite
\details The assign_inverse function initialize a 2D or 3D box with large coordinates, the
min corner is very large, the max corner is very small. This is a convenient starting point to
collect the minimum bounding box of a geometry.
\ingroup assign
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\qbk{
[heading Example]
[assign_inverse] [assign_inverse_output]
[heading See also]
\* [link geometry.reference.algorithms.make.make_inverse make_inverse]
}
*/
template <typename Geometry>
inline void assign_inverse(Geometry& geometry)
{
concepts::check<Geometry>();
dispatch::assign_inverse
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
}
/*!
\brief assign zero values to a box, point
\ingroup assign
\details The assign_zero function initializes a 2D or 3D point or box with coordinates of zero
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
*/
template <typename Geometry>
inline void assign_zero(Geometry& geometry)
{
concepts::check<Geometry>();
dispatch::assign_zero
<
typename tag<Geometry>::type,
Geometry
>::apply(geometry);
}
/*!
\brief Assign two coordinates to a geometry (usually a 2D point)
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param geometry \param_geometry
\param c1 \param_x
\param c2 \param_y
\qbk{distinguish, 2 coordinate values}
\qbk{
[heading Example]
[assign_2d_point] [assign_2d_point_output]
[heading See also]
\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
}
*/
template <typename Geometry, typename Type>
inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
{
concepts::check<Geometry>();
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2);
}
/*!
\brief Assign three values to a geometry (usually a 3D point)
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param geometry \param_geometry
\param c1 \param_x
\param c2 \param_y
\param c3 \param_z
\qbk{distinguish, 3 coordinate values}
\qbk{
[heading Example]
[assign_3d_point] [assign_3d_point_output]
[heading See also]
\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
}
*/
template <typename Geometry, typename Type>
inline void assign_values(Geometry& geometry,
Type const& c1, Type const& c2, Type const& c3)
{
concepts::check<Geometry>();
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2, c3);
}
/*!
\brief Assign four values to a geometry (usually a box or segment)
\ingroup assign
\tparam Geometry \tparam_geometry
\tparam Type \tparam_numeric to specify the coordinates
\param geometry \param_geometry
\param c1 First coordinate (usually x1)
\param c2 Second coordinate (usually y1)
\param c3 Third coordinate (usually x2)
\param c4 Fourth coordinate (usually y2)
\qbk{distinguish, 4 coordinate values}
*/
template <typename Geometry, typename Type>
inline void assign_values(Geometry& geometry,
Type const& c1, Type const& c2, Type const& c3, Type const& c4)
{
concepts::check<Geometry>();
dispatch::assign
<
typename tag<Geometry>::type,
Geometry,
geometry::dimension<Geometry>::type::value
>::apply(geometry, c1, c2, c3, c4);
}
namespace resolve_variant
{
template <typename Geometry1, typename Geometry2>
struct assign
{
static inline void
apply(Geometry1& geometry1, Geometry2 const& geometry2)
{
concepts::check<Geometry1>();
concepts::check<Geometry2 const>();
concepts::check_concepts_and_equal_dimensions<Geometry1, Geometry2 const>();
static bool const same_point_order
= point_order<Geometry1>::value == point_order<Geometry2>::value;
BOOST_GEOMETRY_STATIC_ASSERT(
same_point_order,
"Assign is not supported for different point orders.",
Geometry1, Geometry2);
static bool const same_closure
= closure<Geometry1>::value == closure<Geometry2>::value;
BOOST_GEOMETRY_STATIC_ASSERT(
same_closure,
"Assign is not supported for different closures.",
Geometry1, Geometry2);
dispatch::convert<Geometry2, Geometry1>::apply(geometry2, geometry1);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
struct visitor: static_visitor<void>
{
Geometry2 const& m_geometry2;
visitor(Geometry2 const& geometry2)
: m_geometry2(geometry2)
{}
template <typename Geometry1>
result_type operator()(Geometry1& geometry1) const
{
return assign
<
Geometry1,
Geometry2
>::apply
(geometry1, m_geometry2);
}
};
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry1,
Geometry2 const& geometry2)
{
return boost::apply_visitor(visitor(geometry2), geometry1);
}
};
template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct assign<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
struct visitor: static_visitor<void>
{
Geometry1& m_geometry1;
visitor(Geometry1 const& geometry1)
: m_geometry1(geometry1)
{}
template <typename Geometry2>
result_type operator()(Geometry2 const& geometry2) const
{
return assign
<
Geometry1,
Geometry2
>::apply
(m_geometry1, geometry2);
}
};
static inline void
apply(Geometry1& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2)
{
return boost::apply_visitor(visitor(geometry1), geometry2);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
struct assign<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
{
struct visitor: static_visitor<void>
{
template <typename Geometry1, typename Geometry2>
result_type operator()(
Geometry1& geometry1,
Geometry2 const& geometry2) const
{
return assign
<
Geometry1,
Geometry2
>::apply
(geometry1, geometry2);
}
};
static inline void
apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)>& geometry1,
variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2)
{
return boost::apply_visitor(visitor(), geometry1, geometry2);
}
};
} // namespace resolve_variant
/*!
\brief Assigns one geometry to another geometry
\details The assign algorithm assigns one geometry, e.g. a BOX, to another
geometry, e.g. a RING. This only works if it is possible and applicable.
\ingroup assign
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry (target)
\param geometry2 \param_geometry (source)
\qbk{
[heading Example]
[assign] [assign_output]
[heading See also]
\* [link geometry.reference.algorithms.convert convert]
}
*/
template <typename Geometry1, typename Geometry2>
inline void assign(Geometry1& geometry1, Geometry2 const& geometry2)
{
resolve_variant::assign<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_HPP
+221
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
+24
View File
@@ -0,0 +1,24 @@
// 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_BUFFER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
#include <boost/geometry/algorithms/detail/buffer/interface.hpp>
#include <boost/geometry/algorithms/detail/buffer/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_BUFFER_HPP
+650
View File
@@ -0,0 +1,650 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014-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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
#include <cstddef>
#include <boost/core/ignore_unused.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/throw_exception.hpp>
#include <boost/geometry/core/exception.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/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/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/strategies/detail.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/views/closeable_view.hpp>
namespace boost { namespace geometry
{
#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
/*!
\brief Centroid Exception
\ingroup centroid
\details The centroid_exception is thrown if the free centroid function is called with
geometries for which the centroid cannot be calculated. For example: a linestring
without points, a polygon without points, an empty multi-geometry.
\qbk{
[heading See also]
\* [link geometry.reference.algorithms.centroid the centroid function]
}
*/
class centroid_exception : public geometry::exception
{
public:
inline centroid_exception() {}
char const* what() const noexcept override
{
return "Boost.Geometry Centroid calculation exception";
}
};
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace centroid
{
struct centroid_point
{
template<typename Point, typename PointCentroid, typename Strategy>
static inline void apply(Point const& point, PointCentroid& centroid,
Strategy const&)
{
geometry::convert(point, centroid);
}
};
struct centroid_indexed
{
template<typename Indexed, typename Point, typename Strategy>
static inline void apply(Indexed const& indexed, Point& centroid,
Strategy const&)
{
typedef typename select_coordinate_type
<
Indexed, Point
>::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);
});
}
};
// There is one thing where centroid is different from e.g. within.
// If the ring has only one point, it might make sense that
// that point is the centroid.
template<typename Point, typename Range>
inline bool range_ok(Range const& range, Point& centroid)
{
std::size_t const n = boost::size(range);
if (n > 1)
{
return true;
}
else if (n <= 0)
{
#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
BOOST_THROW_EXCEPTION(centroid_exception());
#else
return false;
#endif
}
else // if (n == 1)
{
// Take over the first point in a "coordinate neutral way"
geometry::convert(*boost::begin(range), centroid);
return false;
}
//return true; // unreachable
}
/*!
\brief Calculate the centroid of a Ring or a Linestring.
*/
struct centroid_range_state
{
template<typename Ring, typename PointTransformer, typename Strategy, typename State>
static inline void apply(Ring const& ring,
PointTransformer const& transformer,
Strategy const& strategy,
State& state)
{
boost::ignore_unused(strategy);
detail::closed_view<Ring const> const view(ring);
auto it = boost::begin(view);
auto const end = boost::end(view);
if (it != end)
{
typename PointTransformer::result_type
previous_pt = transformer.apply(*it);
for ( ++it ; it != end ; ++it)
{
typename PointTransformer::result_type
pt = transformer.apply(*it);
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);
previous_pt = pt;
}
}
}
};
struct centroid_range
{
template<typename Range, typename Point, typename Strategy>
static inline bool apply(Range const& range, Point& centroid,
Strategy const& strategy)
{
if (range_ok(range, centroid))
{
// prepare translation transformer
translating_transformer<Range> transformer(*boost::begin(range));
typename Strategy::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
transformer.apply_reverse(centroid);
return true;
}
}
return false;
}
};
/*!
\brief Centroid of a polygon.
\note Because outer ring is clockwise, inners are counter clockwise,
triangle approach is OK and works for polygons with rings.
*/
struct centroid_polygon_state
{
template<typename Polygon, typename PointTransformer, typename Strategy, typename State>
static inline void apply(Polygon const& poly,
PointTransformer const& transformer,
Strategy const& strategy,
State& state)
{
centroid_range_state::apply(exterior_ring(poly), transformer, strategy, state);
auto const& rings = interior_rings(poly);
auto const end = boost::end(rings);
for (auto it = boost::begin(rings); it != end; ++it)
{
centroid_range_state::apply(*it, transformer, strategy, state);
}
}
};
struct centroid_polygon
{
template<typename Polygon, typename Point, typename Strategy>
static inline bool apply(Polygon const& poly, Point& centroid,
Strategy const& strategy)
{
if (range_ok(exterior_ring(poly), centroid))
{
// prepare translation transformer
translating_transformer<Polygon>
transformer(*boost::begin(exterior_ring(poly)));
typename Strategy::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
transformer.apply_reverse(centroid);
return true;
}
}
return false;
}
};
/*!
\brief Building block of a multi-point, to be used as Policy in the
more generec centroid_multi
*/
struct centroid_multi_point_state
{
template <typename Point, typename PointTransformer, typename Strategy, typename State>
static inline void apply(Point const& point,
PointTransformer const& transformer,
Strategy const& strategy,
State& state)
{
boost::ignore_unused(strategy);
strategy.apply(static_cast<Point const&>(transformer.apply(point)),
state);
}
};
/*!
\brief Generic implementation which calls a policy to calculate the
centroid of the total of its single-geometries
\details The Policy is, in general, the single-version, with state. So
detail::centroid::centroid_polygon_state is used as a policy for this
detail::centroid::centroid_multi
*/
template <typename Policy>
struct centroid_multi
{
template <typename Multi, typename Point, typename Strategy>
static inline bool apply(Multi const& multi,
Point& centroid,
Strategy const& strategy)
{
#if ! defined(BOOST_GEOMETRY_CENTROID_NO_THROW)
// If there is nothing in any of the ranges, it is not possible
// to calculate the centroid
if (geometry::is_empty(multi))
{
BOOST_THROW_EXCEPTION(centroid_exception());
}
#endif
// prepare translation transformer
translating_transformer<Multi> transformer(multi);
typename Strategy::template state_type
<
typename geometry::point_type<Multi>::type,
Point
>::type state;
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
Policy::apply(*it, transformer, strategy, state);
}
if (strategy.result(state, centroid))
{
// translate the result back
transformer.apply_reverse(centroid);
return true;
}
return false;
}
};
template <typename Algorithm>
struct centroid_linear_areal
{
template <typename Geometry, typename Point, typename Strategies>
static inline void apply(Geometry const& geom,
Point& centroid,
Strategies const& strategies)
{
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
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry,
typename Tag = typename tag<Geometry>::type
>
struct centroid: not_implemented<Tag>
{};
template <typename Geometry>
struct centroid<Geometry, point_tag>
: detail::centroid::centroid_point
{};
template <typename Box>
struct centroid<Box, box_tag>
: detail::centroid::centroid_indexed
{};
template <typename Segment>
struct centroid<Segment, segment_tag>
: detail::centroid::centroid_indexed
{};
template <typename Ring>
struct centroid<Ring, ring_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_range
>
{};
template <typename Linestring>
struct centroid<Linestring, linestring_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_range
>
{};
template <typename Polygon>
struct centroid<Polygon, polygon_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_polygon
>
{};
template <typename MultiLinestring>
struct centroid<MultiLinestring, multi_linestring_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_multi
<
detail::centroid::centroid_range_state
>
>
{};
template <typename MultiPolygon>
struct centroid<MultiPolygon, multi_polygon_tag>
: detail::centroid::centroid_linear_areal
<
detail::centroid::centroid_multi
<
detail::centroid::centroid_polygon_state
>
>
{};
template <typename MultiPoint>
struct centroid<MultiPoint, multi_point_tag>
: detail::centroid::centroid_pointlike
<
detail::centroid::centroid_multi
<
detail::centroid::centroid_multi_point_state
>
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy {
template
<
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct centroid
{
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)
{
using strategies::centroid::services::strategy_converter;
dispatch::centroid
<
Geometry
>::apply(geometry, out, strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct centroid<default_strategy, false>
{
template <typename Geometry, typename Point>
static inline void apply(Geometry const& geometry, Point& out, default_strategy)
{
typedef typename strategies::centroid::services::default_strategy
<
Geometry
>::type strategies_type;
dispatch::centroid<Geometry>::apply(geometry, out, strategies_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic {
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<Strategy>::apply(geometry, out, strategy);
}
};
template <typename Geometry>
struct centroid<Geometry, dynamic_geometry_tag>
{
template <typename Point, typename Strategy>
static inline void apply(Geometry const& geometry,
Point& out,
Strategy const& strategy)
{
traits::visit<Geometry>::apply([&](auto const& g)
{
centroid<util::remove_cref_t<decltype(g)>>::apply(g, out, strategy);
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_strategy_reasons
\tparam Geometry \tparam_geometry
\tparam Point \tparam_point
\tparam Strategy \tparam_strategy{Centroid}
\param geometry \param_geometry
\param c \param_point \param_set{centroid}
\param strategy \param_strategy{centroid}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/centroid.qbk]}
\qbk{[include reference/algorithms/centroid_strategies.qbk]}
}
*/
template<typename Geometry, typename Point, typename Strategy>
inline void centroid(Geometry const& geometry, Point& c, Strategy const& strategy)
{
resolve_dynamic::centroid<Geometry>::apply(geometry, c, strategy);
}
/*!
\brief \brief_calc{centroid}
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_default_strategy
\tparam Geometry \tparam_geometry
\tparam Point \tparam_point
\param geometry \param_geometry
\param c The calculated centroid will be assigned to this point reference
\qbk{[include reference/algorithms/centroid.qbk]}
\qbk{
[heading Example]
[centroid]
[centroid_output]
}
*/
template<typename Geometry, typename Point>
inline void centroid(Geometry const& geometry, Point& c)
{
geometry::centroid(geometry, c, default_strategy());
}
/*!
\brief \brief_calc{centroid}
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}.
\tparam Point \tparam_point
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{centroid}
\qbk{[include reference/algorithms/centroid.qbk]}
*/
template<typename Point, typename Geometry>
inline Point return_centroid(Geometry const& geometry)
{
Point c;
geometry::centroid(geometry, c);
return c;
}
/*!
\brief \brief_calc{centroid} \brief_strategy
\ingroup centroid
\details \details_calc{centroid,geometric center (or: center of mass)}. \details_return{centroid}. \details_strategy_reasons
\tparam Point \tparam_point
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{centroid}
\param geometry \param_geometry
\param strategy \param_strategy{centroid}
\return \return_calc{centroid}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/centroid.qbk]}
\qbk{[include reference/algorithms/centroid_strategies.qbk]}
*/
template<typename Point, typename Geometry, typename Strategy>
inline Point return_centroid(Geometry const& geometry, Strategy const& strategy)
{
Point c;
geometry::centroid(geometry, c, strategy);
return c;
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CENTROID_HPP
+190
View File
@@ -0,0 +1,190 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2020-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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
#include <type_traits>
#include <boost/geometry/algorithms/not_implemented.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>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace clear
{
template <typename Geometry>
struct collection_clear
{
static inline void apply(Geometry& geometry)
{
traits::clear<Geometry>::apply(geometry);
}
};
template <typename Polygon>
struct polygon_clear
{
static inline void apply(Polygon& polygon)
{
traits::clear
<
typename std::remove_reference
<
typename traits::interior_mutable_type<Polygon>::type
>::type
>::apply(interior_rings(polygon));
traits::clear
<
typename std::remove_reference
<
typename traits::ring_mutable_type<Polygon>::type
>::type
>::apply(exterior_ring(polygon));
}
};
template <typename Geometry>
struct no_action
{
static inline void apply(Geometry& )
{
}
};
}} // namespace detail::clear
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry,
typename Tag = typename tag_cast<typename tag<Geometry>::type, multi_tag>::type
>
struct clear: not_implemented<Tag>
{};
// Point/box/segment do not have clear. So specialize to do nothing.
template <typename Geometry>
struct clear<Geometry, point_tag>
: detail::clear::no_action<Geometry>
{};
template <typename Geometry>
struct clear<Geometry, box_tag>
: detail::clear::no_action<Geometry>
{};
template <typename Geometry>
struct clear<Geometry, segment_tag>
: detail::clear::no_action<Geometry>
{};
template <typename Geometry>
struct clear<Geometry, linestring_tag>
: detail::clear::collection_clear<Geometry>
{};
template <typename Geometry>
struct clear<Geometry, ring_tag>
: detail::clear::collection_clear<Geometry>
{};
// Polygon can (indirectly) use std for clear
template <typename Polygon>
struct clear<Polygon, polygon_tag>
: detail::clear::polygon_clear<Polygon>
{};
template <typename Geometry>
struct clear<Geometry, multi_tag>
: detail::clear::collection_clear<Geometry>
{};
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);
}
};
template <typename Geometry>
struct clear<Geometry, geometry_collection_tag>
{
static void apply(Geometry& geometry)
{
traits::clear<Geometry>::apply(geometry);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
/*!
\brief Clears a linestring, ring or polygon (exterior+interiors) or multi*
\details Generic function to clear a geometry. All points will be removed from the collection or collections
making up the geometry. In most cases this is equivalent to the .clear() method of a std::vector<...>. In
the case of a polygon, this clear functionality is automatically called for the exterior ring, and for the
interior ring collection. In the case of a point, boxes and segments, nothing will happen.
\ingroup clear
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be cleared
\note points and boxes cannot be cleared, instead they can be set to zero by "assign_zero"
\qbk{[include reference/algorithms/clear.qbk]}
*/
template <typename Geometry>
inline void clear(Geometry& geometry)
{
concepts::check<Geometry>();
dispatch::clear<Geometry>::apply(geometry);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CLEAR_HPP
+16
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
+25
View File
@@ -0,0 +1,25 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
#include <boost/geometry/algorithms/detail/comparable_distance/interface.hpp>
#include <boost/geometry/algorithms/detail/comparable_distance/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_COMPARABLE_DISTANCE_HPP
+573
View File
@@ -0,0 +1,573 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017-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
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
#include <cstddef>
#include <type_traits>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/detail/assign_box_corners.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp>
#include <boost/geometry/algorithms/not_implemented.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
{
// Silence warning C4127: conditional expression is constant
// Silence warning C4512: assignment operator could not be generated
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127 4512)
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
template
<
typename Point,
typename Box,
std::size_t Index,
std::size_t Dimension,
std::size_t DimensionCount
>
struct point_to_box
{
static inline void apply(Point const& point, Box& box)
{
typedef typename coordinate_type<Box>::type coordinate_type;
set<Index, Dimension>(box,
boost::numeric_cast<coordinate_type>(get<Dimension>(point)));
point_to_box
<
Point, Box,
Index, Dimension + 1, DimensionCount
>::apply(point, box);
}
};
template
<
typename Point,
typename Box,
std::size_t Index,
std::size_t DimensionCount
>
struct point_to_box<Point, Box, Index, DimensionCount, DimensionCount>
{
static inline void apply(Point const& , Box& )
{}
};
template <typename Box, typename Range, bool Close, bool Reverse>
struct box_to_range
{
static inline void apply(Box const& box, Range& range)
{
traits::resize<Range>::apply(range, Close ? 5 : 4);
assign_box_corners_oriented<Reverse>(box, range);
if (Close)
{
range::at(range, 4) = range::at(range, 0);
}
}
};
template <typename Segment, typename Range>
struct segment_to_range
{
static inline void apply(Segment const& segment, Range& range)
{
traits::resize<Range>::apply(range, 2);
auto it = boost::begin(range);
assign_point_from_index<0>(segment, *it);
++it;
assign_point_from_index<1>(segment, *it);
}
};
template
<
typename Range1,
typename Range2,
bool Reverse = false
>
struct range_to_range
{
struct default_policy
{
template <typename Point1, typename Point2>
static inline void apply(Point1 const& point1, Point2 & point2)
{
geometry::detail::conversion::convert_point_to_point(point1, point2);
}
};
static inline void apply(Range1 const& source, Range2& destination)
{
apply(source, destination, default_policy());
}
template <typename ConvertPointPolicy>
static inline ConvertPointPolicy apply(Range1 const& source, Range2& destination,
ConvertPointPolicy convert_point)
{
geometry::clear(destination);
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 const view(source);
typedef typename boost::range_size<Range1>::type size_type;
size_type n = boost::size(view);
if (geometry::closure<Range2>::value == geometry::open)
{
n--;
}
// If size == 0 && geometry::open <=> n = numeric_limits<size_type>::max()
// but ok, sice below it == end()
size_type i = 0;
for (auto it = boost::begin(view);
it != boost::end(view) && i < n;
++it, ++i)
{
typename boost::range_value<Range2>::type point;
convert_point.apply(*it, point);
range::push_back(destination, point);
}
return convert_point;
}
};
template <typename Polygon1, typename Polygon2>
struct polygon_to_polygon
{
typedef range_to_range
<
typename geometry::ring_type<Polygon1>::type,
typename geometry::ring_type<Polygon2>::type,
geometry::point_order<Polygon1>::value
!= geometry::point_order<Polygon2>::value
> per_ring;
static inline void apply(Polygon1 const& source, Polygon2& destination)
{
// Clearing managed per ring, and in the resizing of interior rings
per_ring::apply(geometry::exterior_ring(source),
geometry::exterior_ring(destination));
// Container should be resizeable
traits::resize
<
typename std::remove_reference
<
typename traits::interior_mutable_type<Polygon2>::type
>::type
>::apply(interior_rings(destination), num_interior_rings(source));
auto const& rings_source = interior_rings(source);
auto&& rings_dest = interior_rings(destination);
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)
{
per_ring::apply(*it_source, *it_dest);
}
}
};
template <typename Single, typename Multi, typename Policy>
struct single_to_multi: private Policy
{
static inline void apply(Single const& single, Multi& multi)
{
traits::resize<Multi>::apply(multi, 1);
Policy::apply(single, *boost::begin(multi));
}
};
template <typename Multi1, typename Multi2, typename Policy>
struct multi_to_multi: private Policy
{
static inline void apply(Multi1 const& multi1, Multi2& multi2)
{
traits::resize<Multi2>::apply(multi2, boost::size(multi1));
auto it1 = boost::begin(multi1);
auto it2 = boost::begin(multi2);
for (; it1 != boost::end(multi1); ++it1, ++it2)
{
Policy::apply(*it1, *it2);
}
}
};
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// 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 = std::is_same<Geometry1, Geometry2>::value
&& !std::is_array<Geometry1>::value
>
struct convert
: not_implemented
<
Tag1, Tag2,
std::integral_constant<std::size_t, DimensionCount>
>
{};
template
<
typename Geometry1, typename Geometry2,
typename Tag,
std::size_t DimensionCount
>
struct convert<Geometry1, Geometry2, Tag, Tag, DimensionCount, true>
{
// Same geometry type -> copy whole geometry
static inline void apply(Geometry1 const& source, Geometry2& destination)
{
destination = source;
}
};
template
<
typename Geometry1, typename Geometry2,
std::size_t DimensionCount
>
struct convert<Geometry1, Geometry2, point_tag, point_tag, DimensionCount, false>
: detail::conversion::point_to_point<Geometry1, Geometry2, 0, DimensionCount>
{};
template
<
typename Box1, typename Box2,
std::size_t DimensionCount
>
struct convert<Box1, Box2, box_tag, box_tag, DimensionCount, false>
: detail::conversion::indexed_to_indexed<Box1, Box2, 0, DimensionCount>
{};
template
<
typename Segment1, typename Segment2,
std::size_t DimensionCount
>
struct convert<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, false>
: detail::conversion::indexed_to_indexed<Segment1, Segment2, 0, DimensionCount>
{};
template <typename Segment, typename LineString, std::size_t DimensionCount>
struct convert<Segment, LineString, segment_tag, linestring_tag, DimensionCount, false>
: detail::conversion::segment_to_range<Segment, LineString>
{};
template <typename Ring1, typename Ring2, std::size_t DimensionCount>
struct convert<Ring1, Ring2, ring_tag, ring_tag, DimensionCount, false>
: detail::conversion::range_to_range
<
Ring1,
Ring2,
geometry::point_order<Ring1>::value
!= geometry::point_order<Ring2>::value
>
{};
template <typename LineString1, typename LineString2, std::size_t DimensionCount>
struct convert<LineString1, LineString2, linestring_tag, linestring_tag, DimensionCount, false>
: detail::conversion::range_to_range<LineString1, LineString2>
{};
template <typename Polygon1, typename Polygon2, std::size_t DimensionCount>
struct convert<Polygon1, Polygon2, polygon_tag, polygon_tag, DimensionCount, false>
: detail::conversion::polygon_to_polygon<Polygon1, Polygon2>
{};
template <typename Box, typename Ring>
struct convert<Box, Ring, box_tag, ring_tag, 2, false>
: detail::conversion::box_to_range
<
Box,
Ring,
geometry::closure<Ring>::value == closed,
geometry::point_order<Ring>::value == counterclockwise
>
{};
template <typename Box, typename Polygon>
struct convert<Box, Polygon, box_tag, polygon_tag, 2, false>
{
static inline void apply(Box const& box, Polygon& polygon)
{
typedef typename ring_type<Polygon>::type ring_type;
convert
<
Box, ring_type,
box_tag, ring_tag,
2, false
>::apply(box, exterior_ring(polygon));
}
};
template <typename Point, typename Box, std::size_t DimensionCount>
struct convert<Point, Box, point_tag, box_tag, DimensionCount, false>
{
static inline void apply(Point const& point, Box& box)
{
detail::conversion::point_to_box
<
Point, Box, min_corner, 0, DimensionCount
>::apply(point, box);
detail::conversion::point_to_box
<
Point, Box, max_corner, 0, DimensionCount
>::apply(point, box);
}
};
template <typename Ring, typename Polygon, std::size_t DimensionCount>
struct convert<Ring, Polygon, ring_tag, polygon_tag, DimensionCount, false>
{
static inline void apply(Ring const& ring, Polygon& polygon)
{
typedef typename ring_type<Polygon>::type ring_type;
convert
<
Ring, ring_type,
ring_tag, ring_tag,
DimensionCount, false
>::apply(ring, exterior_ring(polygon));
}
};
template <typename Polygon, typename Ring, std::size_t DimensionCount>
struct convert<Polygon, Ring, polygon_tag, ring_tag, DimensionCount, false>
{
static inline void apply(Polygon const& polygon, Ring& ring)
{
typedef typename ring_type<Polygon>::type ring_type;
convert
<
ring_type, Ring,
ring_tag, ring_tag,
DimensionCount, false
>::apply(exterior_ring(polygon), ring);
}
};
// Dispatch for multi <-> multi, specifying their single-version as policy.
// Note that, even if the multi-types are mutually different, their single
// version types might be the same and therefore we call std::is_same again
template <typename Multi1, typename Multi2, std::size_t DimensionCount>
struct convert<Multi1, Multi2, multi_tag, multi_tag, DimensionCount, false>
: detail::conversion::multi_to_multi
<
Multi1,
Multi2,
convert
<
typename boost::range_value<Multi1>::type,
typename boost::range_value<Multi2>::type,
typename single_tag_of
<
typename tag<Multi1>::type
>::type,
typename single_tag_of
<
typename tag<Multi2>::type
>::type,
DimensionCount
>
>
{};
template <typename Single, typename Multi, typename SingleTag, std::size_t DimensionCount>
struct convert<Single, Multi, SingleTag, multi_tag, DimensionCount, false>
: detail::conversion::single_to_multi
<
Single,
Multi,
convert
<
Single,
typename boost::range_value<Multi>::type,
typename tag<Single>::type,
typename single_tag_of
<
typename tag<Multi>::type
>::type,
DimensionCount,
false
>
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant {
template <typename Geometry1, typename Geometry2>
struct convert
{
static inline void apply(Geometry1 const& geometry1, Geometry2& geometry2)
{
concepts::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2>();
dispatch::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
struct convert<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
{
struct visitor: static_visitor<void>
{
Geometry2& m_geometry2;
visitor(Geometry2& geometry2)
: m_geometry2(geometry2)
{}
template <typename Geometry1>
inline void operator()(Geometry1 const& geometry1) const
{
convert<Geometry1, Geometry2>::apply(geometry1, m_geometry2);
}
};
static inline void apply(
boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
Geometry2& geometry2
)
{
boost::apply_visitor(visitor(geometry2), geometry1);
}
};
}
/*!
\brief Converts one geometry to another geometry
\details The convert algorithm converts one geometry, e.g. a BOX, to another
geometry, e.g. a RING. This only works if it is possible and applicable.
If the point-order is different, or the closure is different between two
geometry types, it will be converted correctly by explicitly reversing the
points or closing or opening the polygon rings.
\ingroup convert
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry (source)
\param geometry2 \param_geometry (target)
\qbk{[include reference/algorithms/convert.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline void convert(Geometry1 const& geometry1, Geometry2& geometry2)
{
resolve_variant::convert<Geometry1, Geometry2>::apply(geometry1, geometry2);
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVERT_HPP
+27
View File
@@ -0,0 +1,27 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014, 2015, 2020.
// Modifications copyright (c) 2014-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// 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_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_HPP
#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
+344
View File
@@ -0,0 +1,344 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017-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
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP
#include <algorithm>
#include <functional>
#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/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
{
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace correct
{
struct correct_nop
{
template <typename Geometry, typename Strategy>
static inline void apply(Geometry& , Strategy const& )
{}
};
// Correct a box: make min/max correct
struct correct_box
{
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
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 Predicate = std::less<>>
struct correct_ring
{
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::apply(r);
// NOTE: calculate_point_order should probably be used here instead.
// Check area
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));
}
}
};
// Correct a polygon: normalizes all rings, sets outer ring clockwise, sets all
// inner rings counter clockwise (or vice versa depending on orientation)
struct correct_polygon
{
template <typename Polygon, typename Strategy>
static inline void apply(Polygon& poly, Strategy const& strategy)
{
correct_ring<std::less<>>::apply(exterior_ring(poly), strategy);
auto&& rings = interior_rings(poly);
auto const end = boost::end(rings);
for (auto it = boost::begin(rings); it != end; ++it)
{
correct_ring<std::greater<>>::apply(*it, strategy);
}
}
};
}} // namespace detail::correct
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct correct: not_implemented<Tag>
{};
template <typename Point>
struct correct<Point, point_tag>
: detail::correct::correct_nop
{};
template <typename LineString>
struct correct<LineString, linestring_tag>
: detail::correct::correct_nop
{};
template <typename Segment>
struct correct<Segment, segment_tag>
: detail::correct::correct_nop
{};
template <typename Box>
struct correct<Box, box_tag>
: detail::correct::correct_box
{};
template <typename Ring>
struct correct<Ring, ring_tag>
: detail::correct::correct_ring<>
{};
template <typename Polygon>
struct correct<Polygon, polygon_tag>
: detail::correct::correct_polygon
{};
template <typename MultiPoint>
struct correct<MultiPoint, multi_point_tag>
: detail::correct::correct_nop
{};
template <typename MultiLineString>
struct correct<MultiLineString, multi_linestring_tag>
: detail::correct::correct_nop
{};
template <typename Geometry>
struct correct<Geometry, multi_polygon_tag>
: detail::multi_modify<detail::correct::correct_polygon>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
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>();
resolve_strategy::correct<Strategy>::apply(geometry, strategy);
}
};
template <typename Geometry>
struct correct<Geometry, dynamic_geometry_tag>
{
template <typename Strategy>
static inline void apply(Geometry& geometry, Strategy const& strategy)
{
traits::visit<Geometry>::apply([&](auto & g)
{
correct<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
}, geometry);
}
};
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
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
to their expected orientation are reversed. To all rings which do not have a
closing point and are typed as they should have one, the first point is
appended. Also boxes can be corrected.
\ingroup correct
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be corrected if necessary
\qbk{[include reference/algorithms/correct.qbk]}
*/
template <typename Geometry>
inline void correct(Geometry& geometry)
{
resolve_dynamic::correct<Geometry>::apply(geometry, default_strategy());
}
/*!
\brief Corrects a geometry
\details Corrects a geometry: all rings which are wrongly oriented with respect
to their expected orientation are reversed. To all rings which do not have a
closing point and are typed as they should have one, the first point is
appended. Also boxes can be corrected.
\ingroup correct
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Area}
\param geometry \param_geometry which will be corrected if necessary
\param strategy \param_strategy{area}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/correct.qbk]}
*/
template <typename Geometry, typename Strategy>
inline void correct(Geometry& geometry, Strategy const& strategy)
{
resolve_dynamic::correct<Geometry>::apply(geometry, strategy);
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_HPP
+233
View File
@@ -0,0 +1,233 @@
// Boost.Geometry
// 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)
#ifndef BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_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/tags.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/range/size.hpp>
namespace boost { namespace geometry
{
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace correct_closure
{
struct nop
{
template <typename Geometry>
static inline void apply(Geometry& )
{}
};
// Close a ring, if not closed, or open it
struct close_or_open_ring
{
template <typename Ring>
static inline void apply(Ring& r)
{
auto size = boost::size(r);
if (size <= 2)
{
return;
}
// 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 && closure == closed)
{
// Close it by adding first point
geometry::append(r, *boost::begin(r));
}
else if (! disjoint && closure == open)
{
// Open it by removing last point
range::resize(r, size - 1);
}
}
};
// Close/open exterior ring and all its interior rings
struct close_or_open_polygon
{
template <typename Polygon>
static inline void apply(Polygon& poly)
{
close_or_open_ring::apply(exterior_ring(poly));
auto&& rings = interior_rings(poly);
auto const end = boost::end(rings);
for (auto it = boost::begin(rings); it != end; ++it)
{
close_or_open_ring::apply(*it);
}
}
};
}} // namespace detail::correct_closure
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct correct_closure: not_implemented<Tag>
{};
template <typename Point>
struct correct_closure<Point, point_tag>
: detail::correct_closure::nop
{};
template <typename LineString>
struct correct_closure<LineString, linestring_tag>
: detail::correct_closure::nop
{};
template <typename Segment>
struct correct_closure<Segment, segment_tag>
: detail::correct_closure::nop
{};
template <typename Box>
struct correct_closure<Box, box_tag>
: detail::correct_closure::nop
{};
template <typename Ring>
struct correct_closure<Ring, ring_tag>
: detail::correct_closure::close_or_open_ring
{};
template <typename Polygon>
struct correct_closure<Polygon, polygon_tag>
: detail::correct_closure::close_or_open_polygon
{};
template <typename MultiPoint>
struct correct_closure<MultiPoint, multi_point_tag>
: detail::correct_closure::nop
{};
template <typename MultiLineString>
struct correct_closure<MultiLineString, multi_linestring_tag>
: detail::correct_closure::nop
{};
template <typename Geometry>
struct correct_closure<Geometry, multi_polygon_tag>
: detail::multi_modify
<
detail::correct_closure::close_or_open_polygon
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct correct_closure
{
static inline void apply(Geometry& geometry)
{
concepts::check<Geometry const>();
dispatch::correct_closure<Geometry>::apply(geometry);
}
};
template <typename Geometry>
struct correct_closure<Geometry, dynamic_geometry_tag>
{
static void apply(Geometry& geometry)
{
traits::visit<Geometry>::apply([](auto & g)
{
correct_closure<util::remove_cref_t<decltype(g)>>::apply(g);
}, geometry);
}
};
template <typename Geometry>
struct correct_closure<Geometry, geometry_collection_tag>
{
static void apply(Geometry& 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
have a closing point and are typed as they should have one, the first point
is appended.
\ingroup correct_closure
\tparam Geometry \tparam_geometry
\param geometry \param_geometry which will be corrected if necessary
*/
template <typename Geometry>
inline void correct_closure(Geometry& geometry)
{
resolve_variant::correct_closure<Geometry>::apply(geometry);
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CORRECT_CLOSURE_HPP
+28
View File
@@ -0,0 +1,28 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2013-2022.
// Modifications copyright (c) 2013-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_COVERED_BY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/covered_by/implementation_gc.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
+354
View File
@@ -0,0 +1,354 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2014-2022.
// Modifications copyright (c) 2014-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_CROSSES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
#include <cstddef>
#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
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
struct crosses
: detail::relate::relate_impl
<
detail::de9im::static_mask_crosses_type,
Geometry1,
Geometry2
>
{};
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
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct crosses
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return dispatch::crosses
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
};
template <typename 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 strategies::crosses::services::default_strategy
typedef typename strategies::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return crosses
<
strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic
{
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 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)
{
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
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Crosses}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{crosses}
\return \return_check2{crosses}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/crosses.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool crosses(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_dynamic::crosses
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
/*!
\brief \brief_check2{crosses}
\ingroup crosses
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{crosses}
\qbk{[include reference/algorithms/crosses.qbk]}
\qbk{
[heading Examples]
[crosses]
[crosses_output]
}
*/
template <typename Geometry1, typename Geometry2>
inline bool crosses(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return resolve_dynamic::crosses
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CROSSES_HPP
+41
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
+504
View File
@@ -0,0 +1,504 @@
// Boost.Geometry
// 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.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DENSIFY_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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace densify
{
template <typename Range>
struct push_back_policy
{
typedef typename boost::range_value<Range>::type point_type;
inline explicit push_back_policy(Range & rng)
: m_rng(rng)
{}
inline void apply(point_type const& p)
{
range::push_back(m_rng, p);
}
private:
Range & m_rng;
};
template <typename Range, typename Point>
inline void convert_and_push_back(Range & range, Point const& p)
{
typename boost::range_value<Range>::type p2;
geometry::detail::conversion::convert_point_to_point(p, p2);
range::push_back(range, p2);
}
template <bool AppendLastPoint = true>
struct densify_range
{
template <typename FwdRng, typename MutRng, typename T, typename Strategies>
static inline void apply(FwdRng const& rng, MutRng & rng_out,
T const& len, Strategies const& strategies)
{
typedef typename boost::range_value<FwdRng>::type point_t;
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);
auto prev = it;
for ( ++it ; it != end ; prev = it++)
{
point_t const& p0 = *prev;
point_t const& p1 = *it;
convert_and_push_back(rng_out, p0);
strategy.apply(p0, p1, policy, len);
}
if BOOST_GEOMETRY_CONSTEXPR (AppendLastPoint)
{
convert_and_push_back(rng_out, *prev); // back(rng)
}
}
};
template <bool IsClosed1, bool IsClosed2> // false, X
struct densify_ring
{
template <typename Geometry, typename GeometryOut, typename T, typename Strategies>
static inline void apply(Geometry const& ring, GeometryOut & ring_out,
T const& len, Strategies const& strategies)
{
geometry::detail::densify::densify_range<true>
::apply(ring, ring_out, len, strategies);
if (boost::size(ring) <= 1)
return;
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_CONSTEXPR (IsClosed2)
{
convert_and_push_back(ring_out, p1);
}
}
};
template <>
struct densify_ring<true, true>
: densify_range<true>
{};
template <>
struct densify_ring<true, false>
: densify_range<false>
{};
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
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry,
typename GeometryOut,
typename Tag1 = typename tag<Geometry>::type,
typename Tag2 = typename tag<GeometryOut>::type
>
struct densify
: not_implemented<Tag1, Tag2>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, 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<>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, multi_linestring_tag, multi_linestring_tag>
{
template <typename T, typename Strategy>
static void apply(Geometry const& mls, GeometryOut & mls_out,
T const& len, Strategy const& strategy)
{
std::size_t count = boost::size(mls);
range::resize(mls_out, count);
for (std::size_t i = 0 ; i < count ; ++i)
{
geometry::detail::densify::densify_range<>
::apply(range::at(mls, i), range::at(mls_out, i),
len, strategy);
}
}
};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, ring_tag, ring_tag>
: geometry::detail::densify::densify_ring
<
geometry::closure<Geometry>::value != geometry::open,
geometry::closure<GeometryOut>::value != geometry::open
>
{};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, polygon_tag, polygon_tag>
{
template <typename T, typename Strategy>
static void apply(Geometry const& poly, GeometryOut & poly_out,
T const& len, Strategy const& strategy)
{
apply_ring(exterior_ring(poly), exterior_ring(poly_out),
len, strategy);
std::size_t count = boost::size(interior_rings(poly));
range::resize(interior_rings(poly_out), count);
for (std::size_t i = 0 ; i < count ; ++i)
{
apply_ring(range::at(interior_rings(poly), i),
range::at(interior_rings(poly_out), i),
len, strategy);
}
}
template <typename Ring, typename RingOut, typename T, typename Strategy>
static void apply_ring(Ring const& ring, RingOut & ring_out,
T const& len, Strategy const& strategy)
{
densify<Ring, RingOut, ring_tag, ring_tag>
::apply(ring, ring_out, len, strategy);
}
};
template <typename Geometry, typename GeometryOut>
struct densify<Geometry, GeometryOut, multi_polygon_tag, multi_polygon_tag>
{
template <typename T, typename Strategy>
static void apply(Geometry const& mpoly, GeometryOut & mpoly_out,
T const& len, Strategy const& strategy)
{
std::size_t count = boost::size(mpoly);
range::resize(mpoly_out, count);
for (std::size_t i = 0 ; i < count ; ++i)
{
apply_poly(range::at(mpoly, i),
range::at(mpoly_out, i),
len, strategy);
}
}
template <typename Poly, typename PolyOut, typename T, typename Strategy>
static void apply_poly(Poly const& poly, PolyOut & poly_out,
T const& len, Strategy const& strategy)
{
densify<Poly, PolyOut, polygon_tag, polygon_tag>::
apply(poly, poly_out, len, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template
<
typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct densify
{
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)
{
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 const&)
{
typedef typename strategies::densify::services::default_strategy
<
Geometry
>::type strategies_type;
dispatch::densify
<
Geometry, Geometry
>::apply(geometry, out, max_distance, strategies_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic {
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct densify
{
template <typename Distance, typename Strategy>
static inline void apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
resolve_strategy::densify
<
Strategy
>::apply(geometry, out, max_distance, strategy);
}
};
template <typename Geometry>
struct densify<Geometry, dynamic_geometry_tag>
{
template <typename Distance, typename Strategy>
static inline void
apply(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
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);
}
};
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
/*!
\brief Densify a geometry using a specified strategy
\ingroup densify
\tparam Geometry \tparam_geometry
\tparam Distance A numerical distance measure
\tparam Strategy A type fulfilling a DensifyStrategy concept
\param geometry Input geometry, to be densified
\param out Output geometry, densified version of the input geometry
\param max_distance Distance threshold (in units depending on strategy)
\param strategy Densify strategy to be used for densification
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/densify.qbk]}
\qbk{
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_densify_cartesian Cartesian]
\* [link geometry.reference.strategies.strategy_densify_spherical Spherical]
\* [link geometry.reference.strategies.strategy_densify_geographic Geographic]
[heading Example]
[densify_strategy]
[densify_strategy_output]
[heading See also]
\* [link geometry.reference.algorithms.line_interpolate line_interpolate]
}
*/
template <typename Geometry, typename Distance, typename Strategy>
inline void densify(Geometry const& geometry,
Geometry& out,
Distance const& max_distance,
Strategy const& strategy)
{
concepts::check<Geometry>();
if (max_distance <= Distance(0))
{
BOOST_THROW_EXCEPTION(geometry::invalid_input_exception());
}
geometry::clear(out);
resolve_dynamic::densify
<
Geometry
>::apply(geometry, out, max_distance, strategy);
}
/*!
\brief Densify a geometry
\ingroup densify
\tparam Geometry \tparam_geometry
\tparam Distance A numerical distance measure
\param geometry Input geometry, to be densified
\param out Output geometry, densified version of the input geometry
\param max_distance Distance threshold (in units depending on coordinate system)
\qbk{[include reference/algorithms/densify.qbk]}
\qbk{
[heading Example]
[densify]
[densify_output]
[heading See also]
\* [link geometry.reference.algorithms.line_interpolate line_interpolate]
}
*/
template <typename Geometry, typename Distance>
inline void densify(Geometry const& geometry,
Geometry& out,
Distance const& max_distance)
{
densify(geometry, out, max_distance, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP
@@ -0,0 +1,107 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
#include <cstddef>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/assign_values.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
// Note: this is moved to namespace detail because the names and parameter orders
// are not yet 100% clear.
/*!
\brief Assign the four points of a 2D box
\ingroup assign
\note The order is crucial. Most logical is LOWER, UPPER and sub-order LEFT, RIGHT
so this is how it is implemented.
\tparam Box \tparam_box
\tparam Point \tparam_point
\param box \param_box
\param lower_left point being assigned to lower left coordinates of the box
\param lower_right point being assigned to lower right coordinates of the box
\param upper_left point being assigned to upper left coordinates of the box
\param upper_right point being assigned to upper right coordinates of the box
\qbk{
[heading Example]
[assign_box_corners] [assign_box_corners_output]
}
*/
template <typename Box, typename Point>
inline void assign_box_corners(Box const& box,
Point& lower_left, Point& lower_right,
Point& upper_left, Point& upper_right)
{
concepts::check<Box const>();
concepts::check<Point>();
detail::assign::assign_box_2d_corner
<min_corner, min_corner>(box, lower_left);
detail::assign::assign_box_2d_corner
<max_corner, min_corner>(box, lower_right);
detail::assign::assign_box_2d_corner
<min_corner, max_corner>(box, upper_left);
detail::assign::assign_box_2d_corner
<max_corner, max_corner>(box, upper_right);
}
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
template <bool Reverse, typename Box, typename Range>
inline void assign_box_corners_oriented(Box const& box, Range& corners)
{
if (Reverse)
{
// make counterclockwise ll,lr,ur,ul
assign_box_corners(box,
range::at(corners, 0), range::at(corners, 1),
range::at(corners, 3), range::at(corners, 2));
}
else
{
// make clockwise ll,ul,ur,lr
assign_box_corners(box,
range::at(corners, 0), range::at(corners, 3),
range::at(corners, 1), range::at(corners, 2));
}
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
@@ -0,0 +1,110 @@
// 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 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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
#include <cstddef>
#include <boost/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/util/algorithm.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
/*!
\brief Assign a box or segment with the value of a point
\ingroup assign
\tparam Index indicates which box-corner, min_corner (0) or max_corner (1)
or which point of segment (0/1)
\tparam Point \tparam_point
\tparam Geometry \tparam_box_or_segment
\param point \param_point
\param geometry \param_box_or_segment
\qbk{
[heading Example]
[assign_point_to_index] [assign_point_to_index_output]
}
*/
template <std::size_t Index, typename Geometry, typename Point>
inline void assign_point_to_index(Point const& point, Geometry& geometry)
{
concepts::check<Point const>();
concepts::check<Geometry>();
detail::for_each_dimension<Geometry>([&](auto dimension)
{
geometry::set<Index, dimension>(geometry,
boost::numeric_cast
<
typename coordinate_type<Geometry>::type
>(geometry::get<dimension>(point)));
});
}
/*!
\brief Assign a point with a point of a box or segment
\ingroup assign
\tparam Index indicates which box-corner, min_corner (0) or max_corner (1)
or which point of segment (0/1)
\tparam Geometry \tparam_box_or_segment
\tparam Point \tparam_point
\param geometry \param_box_or_segment
\param point \param_point
\qbk{
[heading Example]
[assign_point_from_index] [assign_point_from_index_output]
}
*/
template <std::size_t Index, typename Point, typename Geometry>
inline void assign_point_from_index(Geometry const& geometry, Point& point)
{
concepts::check<Geometry const>();
concepts::check<Point>();
detail::for_each_dimension<Geometry>([&](auto dimension)
{
geometry::set<dimension>(point,
boost::numeric_cast
<
typename coordinate_type<Point>::type
>(geometry::get<Index, dimension>(geometry)));
});
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
+241
View File
@@ -0,0 +1,241 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2018-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
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
#include <cstddef>
#include <type_traits>
#include <boost/concept/requires.hpp>
#include <boost/concept_check.hpp>
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/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>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace assign
{
struct assign_zero_point
{
template <typename Point>
static inline void apply(Point& point)
{
typedef typename coordinate_type<Point>::type coordinate_type;
coordinate_type const zero = 0;
detail::for_each_dimension<Point>([&](auto dimension)
{
set<dimension>(point, zero);
});
}
};
struct assign_inverse_box_or_segment
{
template <typename BoxOrSegment>
static inline void apply(BoxOrSegment& geometry)
{
typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
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);
});
}
};
struct assign_zero_box_or_segment
{
template <typename BoxOrSegment>
static inline void apply(BoxOrSegment& geometry)
{
typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
coordinate_type const zero = 0;
detail::for_each_dimension<BoxOrSegment>([&](auto dimension)
{
set<0, dimension>(geometry, zero);
set<1, dimension>(geometry, zero);
});
}
};
template
<
std::size_t Corner1, std::size_t Corner2,
typename Box, typename Point
>
inline void assign_box_2d_corner(Box const& box, Point& point)
{
// Be sure both are 2-Dimensional
assert_dimension<Box, 2>();
assert_dimension<Point, 2>();
// Copy coordinates
typedef typename coordinate_type<Point>::type coordinate_type;
geometry::set<0>(point, boost::numeric_cast<coordinate_type>(get<Corner1, 0>(box)));
geometry::set<1>(point, boost::numeric_cast<coordinate_type>(get<Corner2, 1>(box)));
}
template <typename Geometry>
struct assign_2d_box_or_segment
{
typedef typename coordinate_type<Geometry>::type coordinate_type;
// Here we assign 4 coordinates to a box of segment
// -> Most logical is: x1,y1,x2,y2
// In case the user reverses x1/x2 or y1/y2, for a box, we could reverse them (THAT IS NOT IMPLEMENTED)
template <typename Type>
static inline void apply(Geometry& geometry,
Type const& x1, Type const& y1, Type const& x2, Type const& y2)
{
geometry::set<0, 0>(geometry, boost::numeric_cast<coordinate_type>(x1));
geometry::set<0, 1>(geometry, boost::numeric_cast<coordinate_type>(y1));
geometry::set<1, 0>(geometry, boost::numeric_cast<coordinate_type>(x2));
geometry::set<1, 1>(geometry, boost::numeric_cast<coordinate_type>(y2));
}
};
}} // namespace detail::assign
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename GeometryTag, typename Geometry, std::size_t DimensionCount>
struct assign
{
BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
"Not or not yet implemented for this Geometry type.",
GeometryTag, Geometry, std::integral_constant<std::size_t, DimensionCount>);
};
template <typename Point>
struct assign<point_tag, Point, 2>
{
typedef typename coordinate_type<Point>::type coordinate_type;
template <typename T>
static inline void apply(Point& point, T const& c1, T const& c2)
{
set<0>(point, boost::numeric_cast<coordinate_type>(c1));
set<1>(point, boost::numeric_cast<coordinate_type>(c2));
}
};
template <typename Point>
struct assign<point_tag, Point, 3>
{
typedef typename coordinate_type<Point>::type coordinate_type;
template <typename T>
static inline void apply(Point& point, T const& c1, T const& c2, T const& c3)
{
set<0>(point, boost::numeric_cast<coordinate_type>(c1));
set<1>(point, boost::numeric_cast<coordinate_type>(c2));
set<2>(point, boost::numeric_cast<coordinate_type>(c3));
}
};
template <typename Box>
struct assign<box_tag, Box, 2>
: detail::assign::assign_2d_box_or_segment<Box>
{};
template <typename Segment>
struct assign<segment_tag, Segment, 2>
: detail::assign::assign_2d_box_or_segment<Segment>
{};
template <typename GeometryTag, typename Geometry>
struct assign_zero {};
template <typename Point>
struct assign_zero<point_tag, Point>
: detail::assign::assign_zero_point
{};
template <typename Box>
struct assign_zero<box_tag, Box>
: detail::assign::assign_zero_box_or_segment
{};
template <typename Segment>
struct assign_zero<segment_tag, Segment>
: detail::assign::assign_zero_box_or_segment
{};
template <typename GeometryTag, typename Geometry>
struct assign_inverse {};
template <typename Box>
struct assign_inverse<box_tag, Box>
: detail::assign::assign_inverse_box_or_segment
{};
template <typename Segment>
struct assign_inverse<segment_tag, Segment>
: detail::assign::assign_inverse_box_or_segment
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
@@ -0,0 +1,62 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2018-2019 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/access.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t D, std::size_t N>
struct box_loop
{
typedef typename coordinate_type<BoxOut>::type coordinate_type;
static inline void apply(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
coordinate_type d = distance;
set<C, D>(box_out, get<C, D>(box_in) + d);
box_loop<BoxIn, BoxOut, T, C, D + 1, N>::apply(box_in, distance, box_out);
}
};
template <typename BoxIn, typename BoxOut, typename T, std::size_t C, std::size_t N>
struct box_loop<BoxIn, BoxOut, T, C, N, N>
{
static inline void apply(BoxIn const&, T const&, BoxOut&) {}
};
// Extends a box with the same amount in all directions
template<typename BoxIn, typename BoxOut, typename T>
inline void buffer_box(BoxIn const& box_in, T const& distance, BoxOut& box_out)
{
assert_dimension_equal<BoxIn, BoxOut>();
static const std::size_t N = dimension<BoxIn>::value;
box_loop<BoxIn, BoxOut, T, min_corner, 0, N>::apply(box_in, -distance, box_out);
box_loop<BoxIn, BoxOut, T, max_corner, 0, N>::apply(box_in, distance, box_out);
}
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_BOX_HPP
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
#include <cstddef>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/strategies/buffer.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
class backtrack_for_buffer
{
public :
typedef detail::overlay::backtrack_state state_type;
template
<
typename Operation,
typename Rings,
typename Turns,
typename Geometry,
typename Strategy,
typename RobustPolicy,
typename Visitor
>
static inline void apply(std::size_t size_at_start,
Rings& rings, typename boost::range_value<Rings>::type& ring,
Turns& turns,
typename boost::range_value<Turns>::type const& /*turn*/,
Operation& operation,
detail::overlay::traverse_error_type /*traverse_error*/,
Geometry const& ,
Geometry const& ,
Strategy const& ,
RobustPolicy const& ,
state_type& state,
Visitor& /*visitor*/
)
{
#if defined(BOOST_GEOMETRY_COUNT_BACKTRACK_WARNINGS)
extern int g_backtrack_warning_count;
g_backtrack_warning_count++;
#endif
//std::cout << "!";
//std::cout << "WARNING " << traverse_error_string(traverse_error) << std::endl;
state.m_good = false;
// Make bad output clean
rings.resize(size_at_start);
ring.clear();
// Reject this as a starting point
operation.visited.set_rejected();
// And clear all visit info
clear_visit_info(turns);
}
};
struct buffer_overlay_visitor
{
public :
void print(char const* /*header*/)
{
}
template <typename Turns>
void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/)
{
}
template <typename Turns>
void print(char const* /*header*/, Turns const& /*turns*/, int /*turn_index*/, int /*op_index*/)
{
}
template <typename Turns>
void visit_turns(int , Turns const& ) {}
template <typename Clusters, typename Turns>
void visit_clusters(Clusters const& , Turns const& ) {}
template <typename Turns, typename Turn, typename Operation>
void visit_traverse(Turns const& /*turns*/, Turn const& /*turn*/, Operation const& /*op*/, const char* /*header*/)
{
}
template <typename Turns, typename Turn, typename Operation>
void visit_traverse_reject(Turns const& , Turn const& , Operation const& ,
detail::overlay::traverse_error_type )
{}
template <typename Rings>
void visit_generated_rings(Rings const& )
{}
};
// Should follow traversal-turn-concept (enrichment, visit structure)
// and adds index in piece vector to find it back
template <typename Point, typename SegmentRatio>
struct buffer_turn_operation
: public detail::overlay::traversal_turn_operation<Point, SegmentRatio>
{
signed_size_type piece_index;
signed_size_type index_in_robust_ring;
inline buffer_turn_operation()
: piece_index(-1)
, index_in_robust_ring(-1)
{}
};
// Version of turn_info for buffer with its turn index and other helper variables
template <typename Point, typename SegmentRatio>
struct buffer_turn_info
: public detail::overlay::turn_info
<
Point,
SegmentRatio,
buffer_turn_operation<Point, SegmentRatio>
>
{
typedef Point point_type;
std::size_t turn_index;
// Information if turn can be used. It is not traversable if it is within
// another piece, or within the original (depending on deflation),
// or (for deflate) if there are not enough points to traverse it.
bool is_turn_traversable;
bool is_linear_end_point;
bool within_original;
signed_size_type count_in_original; // increased by +1 for in ext.ring, -1 for int.ring
inline buffer_turn_info()
: turn_index(0)
, is_turn_traversable(true)
, is_linear_end_point(false)
, within_original(false)
, count_in_original(0)
{}
};
struct buffer_less
{
template <typename Indexed>
inline bool operator()(Indexed const& left, Indexed const& right) const
{
if (! (left.subject->seg_id == right.subject->seg_id))
{
return left.subject->seg_id < right.subject->seg_id;
}
// Both left and right are located on the SAME segment.
if (! (left.subject->fraction == right.subject->fraction))
{
return left.subject->fraction < right.subject->fraction;
}
return left.turn_index < right.turn_index;
}
};
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;
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFER_POLICIES_HPP
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,290 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2015 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2020.
// Modifications copyright (c) 2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
#include <cstddef>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
struct buffered_ring_collection_tag : polygonal_tag, multi_tag
{};
template <typename Ring>
struct buffered_ring : public Ring
{
bool has_concave;
bool has_accepted_intersections;
bool has_discarded_intersections;
bool is_untouched_outside_original;
inline buffered_ring()
: has_concave(false)
, has_accepted_intersections(false)
, has_discarded_intersections(false)
, is_untouched_outside_original(false)
{}
inline bool discarded() const
{
return has_discarded_intersections && ! has_accepted_intersections;
}
inline bool has_intersections() const
{
return has_discarded_intersections || has_accepted_intersections;
}
};
// This is a collection now special for overlay (needs vector of rings)
template <typename Ring>
struct buffered_ring_collection : public std::vector<Ring>
{
};
}} // namespace detail::buffer
// Turn off concept checking (for now)
namespace concepts
{
template <typename Geometry>
struct concept_type<Geometry, geometry::detail::buffer::buffered_ring_collection_tag>
{
struct dummy {};
using type = dummy;
};
}
#endif // DOXYGEN_NO_DETAIL
// Register the types
namespace traits
{
template <typename Ring>
struct tag<geometry::detail::buffer::buffered_ring<Ring> >
{
typedef ring_tag type;
};
template <typename Ring>
struct point_order<geometry::detail::buffer::buffered_ring<Ring> >
{
static const order_selector value = geometry::point_order<Ring>::value;
};
template <typename Ring>
struct closure<geometry::detail::buffer::buffered_ring<Ring> >
{
static const closure_selector value = geometry::closure<Ring>::value;
};
template <typename Ring>
struct point_type<geometry::detail::buffer::buffered_ring_collection<Ring> >
{
typedef typename geometry::point_type<Ring>::type type;
};
template <typename Ring>
struct tag<geometry::detail::buffer::buffered_ring_collection<Ring> >
{
typedef geometry::detail::buffer::buffered_ring_collection_tag type;
};
} // namespace traits
namespace core_dispatch
{
template <typename Ring>
struct ring_type
<
detail::buffer::buffered_ring_collection_tag,
detail::buffer::buffered_ring_collection<Ring>
>
{
typedef Ring type;
};
// There is a specific tag, so this specialization cannot be placed in traits
template <typename Ring>
struct point_order<detail::buffer::buffered_ring_collection_tag,
geometry::detail::buffer::buffered_ring_collection
<
geometry::detail::buffer::buffered_ring<Ring>
> >
{
static const order_selector value
= core_dispatch::point_order<ring_tag, Ring>::value;
};
}
template <>
struct single_tag_of<detail::buffer::buffered_ring_collection_tag>
{
typedef ring_tag type;
};
namespace dispatch
{
template
<
typename MultiRing,
bool Reverse,
typename SegmentIdentifier,
typename PointOut
>
struct copy_segment_point
<
detail::buffer::buffered_ring_collection_tag,
MultiRing,
Reverse,
SegmentIdentifier,
PointOut
>
: detail::copy_segments::copy_segment_point_multi
<
MultiRing,
SegmentIdentifier,
PointOut,
detail::copy_segments::copy_segment_point_range
<
typename boost::range_value<MultiRing>::type,
Reverse,
SegmentIdentifier,
PointOut
>
>
{};
template<bool Reverse>
struct copy_segments
<
detail::buffer::buffered_ring_collection_tag,
Reverse
>
: detail::copy_segments::copy_segments_multi
<
detail::copy_segments::copy_segments_ring<Reverse>
>
{};
template <typename Point, typename MultiGeometry>
struct within
<
Point,
MultiGeometry,
point_tag,
detail::buffer::buffered_ring_collection_tag
>
{
template <typename Strategy>
static inline bool apply(Point const& point,
MultiGeometry const& multi, Strategy const& strategy)
{
return detail::within::point_in_geometry(point, multi, strategy) == 1;
}
};
template <typename Geometry>
struct is_empty<Geometry, detail::buffer::buffered_ring_collection_tag>
: detail::is_empty::multi_is_empty<detail::is_empty::range_is_empty>
{};
template <typename Geometry>
struct envelope<Geometry, detail::buffer::buffered_ring_collection_tag>
: detail::envelope::envelope_multi_range
<
detail::envelope::envelope_range
>
{};
} // namespace dispatch
namespace detail { namespace overlay
{
template<>
struct get_ring<detail::buffer::buffered_ring_collection_tag>
{
template<typename MultiGeometry>
static inline typename ring_type<MultiGeometry>::type const& apply(
ring_identifier const& id,
MultiGeometry const& multi_ring)
{
BOOST_GEOMETRY_ASSERT
(
id.multi_index >= 0
&& id.multi_index < int(boost::size(multi_ring))
);
return get_ring<ring_tag>::apply(id, multi_ring[id.multi_index]);
}
};
}}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_BUFFERED_RING
@@ -0,0 +1,327 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017-2020.
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
#include <boost/geometry/algorithms/detail/sections/section_functions.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
// Implements a unique_sub_range for a buffered piece,
// the range can return subsequent points
// known as "i", "j" and "k" (and further), indexed as 0,1,2,3
template <typename Ring>
struct unique_sub_range_from_piece
{
typedef typename boost::range_iterator<Ring const>::type iterator_type;
typedef typename geometry::point_type<Ring const>::type point_type;
unique_sub_range_from_piece(Ring const& ring,
iterator_type iterator_at_i, iterator_type iterator_at_j)
: m_ring(ring)
, m_iterator_at_i(iterator_at_i)
, m_iterator_at_j(iterator_at_j)
, m_point_retrieved(false)
{}
static inline bool is_first_segment() { return false; }
static inline bool is_last_segment() { return false; }
static inline std::size_t size() { return 3u; }
inline point_type const& at(std::size_t index) const
{
BOOST_GEOMETRY_ASSERT(index < size());
switch (index)
{
case 0 : return *m_iterator_at_i;
case 1 : return *m_iterator_at_j;
case 2 : return get_point_k();
default : return *m_iterator_at_i;
}
}
private :
inline point_type const& get_point_k() const
{
if (! m_point_retrieved)
{
m_iterator_at_k = advance_one(m_iterator_at_j);
m_point_retrieved = true;
}
return *m_iterator_at_k;
}
inline void circular_advance_one(iterator_type& next) const
{
++next;
if (next == boost::end(m_ring))
{
next = boost::begin(m_ring) + 1;
}
}
inline iterator_type advance_one(iterator_type it) const
{
iterator_type result = it;
circular_advance_one(result);
// TODO: we could also use piece-boundaries
// to check if the point equals the last one
while (geometry::equals(*it, *result))
{
circular_advance_one(result);
}
return result;
}
Ring const& m_ring;
iterator_type m_iterator_at_i;
iterator_type m_iterator_at_j;
mutable iterator_type m_iterator_at_k;
mutable bool m_point_retrieved;
};
template
<
typename Pieces,
typename Rings,
typename Turns,
typename Strategy,
typename RobustPolicy
>
class piece_turn_visitor
{
Pieces const& m_pieces;
Rings const& m_rings;
Turns& m_turns;
Strategy const& m_strategy;
RobustPolicy const& m_robust_policy;
template <typename Piece>
inline bool is_adjacent(Piece const& piece1, Piece const& piece2) const
{
if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
{
return false;
}
return piece1.index == piece2.left_index
|| piece1.index == piece2.right_index;
}
template <typename Piece>
inline bool is_on_same_convex_ring(Piece const& piece1, Piece const& piece2) const
{
if (piece1.first_seg_id.multi_index != piece2.first_seg_id.multi_index)
{
return false;
}
return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
signed_size_type& index, int dir,
Box const& this_bounding_box,
Box const& other_bounding_box)
{
for(; it_begin != it_beyond
&& it_begin + 1 != it_beyond
&& detail::section::preceding<Dimension>(dir, *(it_begin + 1),
this_bounding_box,
other_bounding_box,
m_robust_policy);
++it_begin, index++)
{}
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
int dir, Box const& this_bounding_box,
Box const& other_bounding_box)
{
while (it_beyond != it_begin
&& it_beyond - 1 != it_begin
&& it_beyond - 2 != it_begin)
{
if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
this_bounding_box, other_bounding_box, m_robust_policy))
{
--it_beyond;
}
else
{
return;
}
}
}
template <typename Piece, typename Section>
inline void calculate_turns(Piece const& piece1, Piece const& piece2,
Section const& section1, Section const& section2)
{
typedef typename boost::range_value<Rings const>::type ring_type;
typedef typename boost::range_value<Turns const>::type turn_type;
signed_size_type const piece1_first_index = piece1.first_seg_id.segment_index;
signed_size_type const piece2_first_index = piece2.first_seg_id.segment_index;
if (piece1_first_index < 0 || piece2_first_index < 0)
{
return;
}
// Get indices of part of offsetted_rings for this monotonic section:
signed_size_type const sec1_first_index = piece1_first_index + section1.begin_index;
signed_size_type const sec2_first_index = piece2_first_index + section2.begin_index;
// index of last point in section, beyond-end is one further
signed_size_type const sec1_last_index = piece1_first_index + section1.end_index;
signed_size_type const sec2_last_index = piece2_first_index + section2.end_index;
// get geometry and iterators over these sections
ring_type const& ring1 = m_rings[piece1.first_seg_id.multi_index];
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];
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;
move_begin_iterator<0>(it1_first, it1_beyond, index1,
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_end_iterator<0>(it1_first, it1_beyond,
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_begin_iterator<1>(it1_first, it1_beyond, index1,
section1.directions[1], section1.bounding_box, section2.bounding_box);
move_end_iterator<1>(it1_first, it1_beyond,
section1.directions[1], section1.bounding_box, section2.bounding_box);
signed_size_type index2 = sec2_first_index;
move_begin_iterator<0>(it2_first, it2_beyond, index2,
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_end_iterator<0>(it2_first, it2_beyond,
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_begin_iterator<1>(it2_first, it2_beyond, index2,
section2.directions[1], section2.bounding_box, section1.bounding_box);
move_end_iterator<1>(it2_first, it2_beyond,
section2.directions[1], section2.bounding_box, section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;
the_model.operations[0].seg_id = piece1.first_seg_id;
the_model.operations[0].seg_id.segment_index = index1; // override
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
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);
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);
typedef detail::overlay::get_turn_info
<
detail::overlay::assign_policy_only_start_turns
> turn_policy;
turn_policy::apply(unique_sub_range1, unique_sub_range2,
the_model,
m_strategy,
m_robust_policy,
std::back_inserter(m_turns));
}
}
}
public:
piece_turn_visitor(Pieces const& pieces,
Rings const& ring_collection,
Turns& turns,
Strategy const& strategy,
RobustPolicy const& robust_policy)
: m_pieces(pieces)
, m_rings(ring_collection)
, m_turns(turns)
, m_strategy(strategy)
, m_robust_policy(robust_policy)
{}
template <typename Section>
inline bool apply(Section const& section1, Section const& section2,
bool first = true)
{
boost::ignore_unused(first);
typedef typename boost::range_value<Pieces const>::type piece_type;
piece_type const& piece1 = m_pieces[section1.ring_id.source_index];
piece_type const& piece2 = m_pieces[section2.ring_id.source_index];
if ( piece1.index == piece2.index
|| is_adjacent(piece1, piece2)
|| is_on_same_convex_ring(piece1, piece2)
|| detail::disjoint::disjoint_box_box(section1.bounding_box,
section2.bounding_box,
m_strategy) )
{
return true;
}
calculate_turns(piece1, piece2, section1, section2);
return true;
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_GET_PIECE_TURNS_HPP
@@ -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
+279
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
@@ -0,0 +1,120 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
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 bool
apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj,
Point const& vertex, bool equidistant, Point& ip)
{
// 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.
using ct = typename coordinate_type<Point>::type;
auto const p = detail::make::make_infinite_line<ct>(pi, pj);
auto const q = detail::make::make_infinite_line<ct>(qi, qj);
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);
static decltype(denominator_pq) const zero = 0;
if (equidistant)
{
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);
}
return true;
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
@@ -0,0 +1,512 @@
// 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/range/size.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
@@ -0,0 +1,300 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands.
// 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,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
#include <boost/core/ignore_unused.hpp>
#include <boost/range/size.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>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
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>
inline void apply(Box& total, Original const& original) const
{
assert_coordinate_type_equal(total, original.m_box);
geometry::expand(total, original.m_box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct original_overlaps_box
{
explicit original_overlaps_box(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename 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,
m_strategy);
}
Strategy const& m_strategy;
};
struct include_turn_policy
{
template <typename Turn>
static inline bool apply(Turn const& turn)
{
return turn.is_turn_traversable;
}
};
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>
inline bool apply(Box const& box, Turn const& turn) const
{
if (! turn.is_turn_traversable || turn.within_original)
{
// Skip all points already processed
return false;
}
return ! geometry::detail::disjoint::disjoint_point_box(
turn.point, box, m_strategy);
}
Strategy const& m_strategy;
};
//! Check if specified is in range of specified iterators
//! Return value of strategy (true if we can bail out)
template
<
typename Strategy,
typename State,
typename Point,
typename Iterator
>
inline bool point_in_range(Strategy& strategy, State& state,
Point const& point, Iterator begin, Iterator end)
{
boost::ignore_unused(strategy);
Iterator it = begin;
for (Iterator previous = it++; it != end; ++previous, ++it)
{
if (! strategy.apply(point, *previous, *it, state))
{
// We're probably on the boundary
return false;
}
}
return true;
}
template
<
typename Strategy,
typename State,
typename Point,
typename CoordinateType,
typename Iterator
>
inline bool point_in_section(Strategy& strategy, State& state,
Point const& point, CoordinateType const& point_x,
Iterator begin, Iterator end,
int direction)
{
if (direction == 0)
{
// Not a monotonic section, or no change in X-direction
return point_in_range(strategy, state, point, begin, end);
}
// We're in a monotonic section in x-direction
Iterator it = begin;
for (Iterator previous = it++; it != end; ++previous, ++it)
{
// Depending on sections.direction we can quit for this section
CoordinateType const previous_x = geometry::get<0>(*previous);
if (direction == 1 && point_x < previous_x)
{
// Section goes upwards, x increases, point is is below section
return true;
}
else if (direction == -1 && point_x > previous_x)
{
// Section goes downwards, x decreases, point is above section
return true;
}
if (! strategy.apply(point, *previous, *it, state))
{
// We're probably on the boundary
return false;
}
}
return true;
}
template <typename Point, typename Original, typename PointInGeometryStrategy>
inline int point_in_original(Point const& point, Original const& original,
PointInGeometryStrategy const& strategy)
{
typename PointInGeometryStrategy::state_type state;
if (boost::size(original.m_sections) == 0
|| boost::size(original.m_ring) - boost::size(original.m_sections) < 16)
{
// There are no sections, or it does not profit to walk over sections
// instead of over points. Boundary of 16 is arbitrary but can influence
// performance
point_in_range(strategy, state, point,
original.m_ring.begin(), original.m_ring.end());
return strategy.result(state);
}
auto const point_x = geometry::get<0>(point);
// Walk through all monotonic sections of this original
for (auto const& section : original.m_sections)
{
if (! section.duplicate
&& section.begin_index < section.end_index
&& point_x >= geometry::get<min_corner, 0>(section.bounding_box)
&& point_x <= geometry::get<max_corner, 0>(section.bounding_box))
{
// x-coordinate of point overlaps with section
if (! point_in_section(strategy, state, point, point_x,
boost::begin(original.m_ring) + section.begin_index,
boost::begin(original.m_ring) + section.end_index + 1,
section.directions[0]))
{
// We're probably on the boundary
break;
}
}
}
return strategy.result(state);
}
template <typename Turns, typename Strategy>
class turn_in_original_visitor
{
public:
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)
{
if (boost::empty(original.m_ring))
{
// Skip empty rings
return true;
}
if (! turn.is_turn_traversable || turn.within_original)
{
// Skip all points already processed
return true;
}
if (geometry::disjoint(turn.point, original.m_box, m_strategy))
{
// Skip all disjoint
return true;
}
int const code = point_in_original(turn.point, original,
m_strategy.relate(turn.point, original.m_ring));
if (code == -1)
{
return true;
}
Turn& mutable_turn = m_mutable_turns[turn.turn_index];
if (code == 0)
{
// On border of original: always discard
mutable_turn.is_turn_traversable = false;
}
// Point is inside an original ring
if (original.m_is_interior)
{
mutable_turn.count_in_original--;
}
else if (original.m_has_interiors)
{
mutable_turn.count_in_original++;
}
else
{
// It is an exterior ring and there are no interior rings.
// Then we are completely ready with this turn
mutable_turn.within_original = true;
mutable_turn.count_in_original = 1;
}
return true;
}
private :
Turns& m_mutable_turns;
Strategy const& m_strategy;
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_ORIGINAL_VISITOR
@@ -0,0 +1,194 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2016-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_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/algorithms/comparable_distance.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/geometries/box.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace buffer
{
template
<
typename CsTag,
typename Turns,
typename Pieces,
typename DistanceStrategy,
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
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
{
if (op.piece_index == piece.index)
{
return true;
}
Piece const& pc = m_pieces[op.piece_index];
if (pc.left_index == piece.index || pc.right_index == piece.index)
{
if (pc.type == strategy::buffer::buffered_flat_end)
{
// If it is a flat end, don't compare against its neighbor:
// it will always be located on one of the helper segments
return true;
}
if (pc.type == strategy::buffer::buffered_concave)
{
// If it is concave, the same applies: the IP will be
// located on one of the helper segments
return true;
}
}
return false;
}
template <typename NumericType>
inline bool is_one_sided(NumericType const& left, NumericType const& right) const
{
static NumericType const zero = 0;
return geometry::math::equals(left, zero)
|| geometry::math::equals(right, zero);
}
template <typename Point>
inline bool has_zero_distance_at(Point const& point) const
{
return is_one_sided(m_distance_strategy.apply(point, point,
strategy::buffer::buffer_side_left),
m_distance_strategy.apply(point, point,
strategy::buffer::buffer_side_right));
}
public:
inline turn_in_piece_visitor(Turns& turns, Pieces const& pieces,
DistanceStrategy const& distance_strategy,
UmbrellaStrategy const& umbrella_strategy)
: m_turns(turns)
, m_pieces(pieces)
, m_distance_strategy(distance_strategy)
, m_umbrella_strategy(umbrella_strategy)
{}
template <typename Turn, typename Piece>
inline bool apply(Turn const& turn, Piece const& piece)
{
if (! turn.is_turn_traversable)
{
// Already handled
return true;
}
if (piece.type == strategy::buffer::buffered_flat_end
|| piece.type == strategy::buffer::buffered_concave)
{
// Turns cannot be located within flat-end or concave pieces
return true;
}
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
{
return true;
}
return apply(turn, piece, piece.m_piece_border);
}
template <typename Turn, typename Piece, typename Border>
inline bool apply(Turn const& turn, Piece const& piece, Border const& border)
{
if (! geometry::covered_by(turn.point, border.m_envelope, 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 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);
if (d < border.m_min_comparable_radius)
{
Turn& mutable_turn = m_turns[turn.turn_index];
mutable_turn.is_turn_traversable = false;
return true;
}
if (d > border.m_max_comparable_radius)
{
return true;
}
}
// Check if buffer is one-sided (at this point), because then a point
// on the original border is not considered as within.
bool const one_sided = has_zero_distance_at(turn.point);
typename Border::state_type state;
if (! border.point_on_piece(turn.point, one_sided,
turn.is_linear_end_point, state))
{
return true;
}
if (state.is_inside() && ! state.is_on_boundary())
{
Turn& mutable_turn = m_turns[turn.turn_index];
mutable_turn.is_turn_traversable = false;
}
return true;
}
};
}} // namespace detail::buffer
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_TURN_IN_PIECE_VISITOR_HPP
+38
View File
@@ -0,0 +1,38 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
struct calculate_null
{
template<typename ReturnType, typename Geometry, typename Strategy>
static inline ReturnType apply(Geometry const& , Strategy const&)
{
return ReturnType();
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
@@ -0,0 +1,364 @@
// 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/range/size.hpp>
#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
+63
View File
@@ -0,0 +1,63 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2016-2020.
// Modifications copyright (c) 2016-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
class calculate_polygon_sum
{
template <typename ReturnType, typename Policy, typename Rings, typename Strategy>
static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy)
{
ReturnType sum = ReturnType(0);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
sum += Policy::apply(*it, strategy);
}
return sum;
}
public :
template <typename ReturnType, typename Policy, typename Polygon, typename Strategy>
static inline ReturnType apply(Polygon const& poly, Strategy const& strategy)
{
return Policy::apply(exterior_ring(poly), strategy)
+ sum_interior_rings<ReturnType, Policy>(interior_rings(poly), strategy)
;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
@@ -0,0 +1,119 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
#include <cstddef>
#include <boost/core/addressof.hpp>
#include <boost/core/ref.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/arithmetic/arithmetic.hpp>
#include <boost/geometry/iterators/point_iterator.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace centroid
{
// NOTE: There is no need to translate in other coordinate systems than
// cartesian. But if it was needed then one should translate using
// CS-specific technique, e.g. in spherical/geographic a translation
// vector should contain coordinates being multiplies of 2PI or 360 deg.
template <typename Geometry,
typename CastedTag = typename tag_cast
<
typename tag<Geometry>::type,
areal_tag
>::type,
typename CSTag = typename cs_tag<Geometry>::type>
struct translating_transformer
{
typedef typename geometry::point_type<Geometry>::type point_type;
typedef boost::reference_wrapper<point_type const> result_type;
explicit translating_transformer(Geometry const&) {}
explicit translating_transformer(point_type const&) {}
result_type apply(point_type const& pt) const
{
return result_type(pt);
}
template <typename ResPt>
void apply_reverse(ResPt &) const {}
};
// Specialization for Areal Geometries in cartesian CS
template <typename Geometry>
struct translating_transformer<Geometry, areal_tag, cartesian_tag>
{
typedef typename geometry::point_type<Geometry>::type point_type;
typedef point_type result_type;
explicit translating_transformer(Geometry const& geom)
: m_origin(NULL)
{
geometry::point_iterator<Geometry const>
pt_it = geometry::points_begin(geom);
if ( pt_it != geometry::points_end(geom) )
{
m_origin = boost::addressof(*pt_it);
}
}
explicit translating_transformer(point_type const& origin)
: m_origin(boost::addressof(origin))
{}
result_type apply(point_type const& pt) const
{
point_type res = pt;
if ( m_origin )
geometry::subtract_point(res, *m_origin);
return res;
}
template <typename ResPt>
void apply_reverse(ResPt & res_pt) const
{
if ( m_origin )
geometry::add_point(res_pt, *m_origin);
}
const point_type * m_origin;
};
}} // namespace detail::centroid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CENTROID_TRANSLATING_TRANSFORMER_HPP
@@ -0,0 +1,145 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
#include <iterator>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_feature
{
// returns the range iterator the realizes the closest
// distance between the geometry and the element of the range
class geometry_to_range
{
private:
template
<
typename Geometry,
typename RangeIterator,
typename Strategy,
typename Distance
>
static inline void apply(Geometry const& geometry,
RangeIterator first,
RangeIterator last,
Strategy const& strategy,
RangeIterator& it_min,
Distance& dist_min)
{
BOOST_GEOMETRY_ASSERT( first != last );
Distance const zero = Distance(0);
// start with first distance
it_min = first;
dist_min = dispatch::distance
<
Geometry,
typename std::iterator_traits<RangeIterator>::value_type,
Strategy
>::apply(geometry, *it_min, strategy);
// check if other elements in the range are closer
for (RangeIterator it = ++first; it != last; ++it)
{
Distance dist = dispatch::distance
<
Geometry,
typename std::iterator_traits<RangeIterator>::value_type,
Strategy
>::apply(geometry, *it, strategy);
if (geometry::math::equals(dist, zero))
{
dist_min = dist;
it_min = it;
return;
}
else if (dist < dist_min)
{
dist_min = dist;
it_min = it;
}
}
}
public:
template
<
typename Geometry,
typename RangeIterator,
typename Strategy,
typename Distance
>
static inline RangeIterator apply(Geometry const& geometry,
RangeIterator first,
RangeIterator last,
Strategy const& strategy,
Distance& dist_min)
{
RangeIterator it_min;
apply(geometry, first, last, strategy, it_min, dist_min);
return it_min;
}
template
<
typename Geometry,
typename RangeIterator,
typename Strategy
>
static inline RangeIterator apply(Geometry const& geometry,
RangeIterator first,
RangeIterator last,
Strategy const& strategy)
{
typename strategy::distance::services::return_type
<
Strategy,
typename point_type<Geometry>::type,
typename point_type
<
typename std::iterator_traits
<
RangeIterator
>::value_type
>::type
>::type dist_min;
return apply(geometry, first, last, strategy, dist_min);
}
};
}} // namespace detail::closest_feature
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_GEOMETRY_TO_RANGE_HPP
@@ -0,0 +1,257 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
#include <utility>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/util/math.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_feature
{
// returns the segment (pair of iterators) that realizes the closest
// distance of the point to the range
template
<
typename Point,
typename Range,
closure_selector Closure
>
class point_to_point_range
{
protected:
typedef typename boost::range_iterator<Range const>::type iterator_type;
template <typename Strategy, typename Distance>
static inline void apply(Point const& point,
iterator_type first,
iterator_type last,
Strategy const& strategy,
iterator_type& it_min1,
iterator_type& it_min2,
Distance& dist_min)
{
BOOST_GEOMETRY_ASSERT( first != last );
Distance const zero = Distance(0);
iterator_type it = first;
iterator_type prev = it++;
if (it == last)
{
it_min1 = it_min2 = first;
dist_min = strategy.apply(point, *first, *first);
return;
}
// start with first segment distance
dist_min = strategy.apply(point, *prev, *it);
iterator_type prev_min_dist = prev;
// check if other segments are closer
for (++prev, ++it; it != last; ++prev, ++it)
{
Distance const dist = strategy.apply(point, *prev, *it);
// Stop only if we find exactly zero distance
// otherwise it may stop at some very small value and miss the min
if (dist == zero)
{
dist_min = zero;
it_min1 = prev;
it_min2 = it;
return;
}
else if (dist < dist_min)
{
dist_min = dist;
prev_min_dist = prev;
}
}
it_min1 = it_min2 = prev_min_dist;
++it_min2;
}
public:
typedef typename std::pair<iterator_type, iterator_type> return_type;
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
Strategy const& strategy,
Distance& dist_min)
{
iterator_type it_min1, it_min2;
apply(point, first, last, strategy, it_min1, it_min2, dist_min);
return std::make_pair(it_min1, it_min2);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
Strategy const& strategy)
{
typename strategy::distance::services::return_type
<
Strategy,
Point,
typename boost::range_value<Range>::type
>::type dist_min;
return apply(point, first, last, strategy, dist_min);
}
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy,
Distance& dist_min)
{
return apply(point,
boost::begin(range),
boost::end(range),
strategy,
dist_min);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy)
{
return apply(point, boost::begin(range), boost::end(range), strategy);
}
};
// specialization for open ranges
template <typename Point, typename Range>
class point_to_point_range<Point, Range, open>
: point_to_point_range<Point, Range, closed>
{
private:
typedef point_to_point_range<Point, Range, closed> base_type;
typedef typename base_type::iterator_type iterator_type;
template <typename Strategy, typename Distance>
static inline void apply(Point const& point,
iterator_type first,
iterator_type last,
Strategy const& strategy,
iterator_type& it_min1,
iterator_type& it_min2,
Distance& dist_min)
{
BOOST_GEOMETRY_ASSERT( first != last );
base_type::apply(point, first, last, strategy,
it_min1, it_min2, dist_min);
iterator_type it_back = --last;
Distance const zero = Distance(0);
Distance dist = strategy.apply(point, *it_back, *first);
if (geometry::math::equals(dist, zero))
{
dist_min = zero;
it_min1 = it_back;
it_min2 = first;
}
else if (dist < dist_min)
{
dist_min = dist;
it_min1 = it_back;
it_min2 = first;
}
}
public:
typedef typename std::pair<iterator_type, iterator_type> return_type;
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
Strategy const& strategy,
Distance& dist_min)
{
iterator_type it_min1, it_min2;
apply(point, first, last, strategy, it_min1, it_min2, dist_min);
return std::make_pair(it_min1, it_min2);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
iterator_type first,
iterator_type last,
Strategy const& strategy)
{
typedef typename strategy::distance::services::return_type
<
Strategy,
Point,
typename boost::range_value<Range>::type
>::type distance_return_type;
distance_return_type dist_min;
return apply(point, first, last, strategy, dist_min);
}
template <typename Strategy, typename Distance>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy,
Distance& dist_min)
{
return apply(point,
boost::begin(range),
boost::end(range),
strategy,
dist_min);
}
template <typename Strategy>
static inline return_type apply(Point const& point,
Range const& range,
Strategy const& strategy)
{
return apply(point, boost::begin(range), boost::end(range), strategy);
}
};
}} // namespace detail::closest_feature
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_POINT_TO_RANGE_HPP
@@ -0,0 +1,202 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, 2019, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
#include <cstddef>
#include <iterator>
#include <utility>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
#include <boost/geometry/index/rtree.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace closest_feature
{
// returns a pair of a objects where the first is an object of the
// r-tree range and the second an object of the query range that
// realizes the closest feature of the two ranges
class range_to_range_rtree
{
private:
template
<
typename RTreeRangeIterator,
typename QueryRangeIterator,
typename Strategies,
typename RTreeValueType,
typename Distance
>
static inline void apply(RTreeRangeIterator rtree_first,
RTreeRangeIterator rtree_last,
QueryRangeIterator queries_first,
QueryRangeIterator queries_last,
Strategies const& strategies,
RTreeValueType& rtree_min,
QueryRangeIterator& qit_min,
Distance& dist_min)
{
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 );
Distance const zero = Distance(0);
dist_min = zero;
// create -- packing algorithm
rtree_type rt(rtree_first, rtree_last,
index_parameters_type(index::linear<8>(), strategies));
RTreeValueType t_v;
bool first = true;
for (QueryRangeIterator qit = queries_first;
qit != queries_last; ++qit, first = false)
{
std::size_t n = rt.query(index::nearest(*qit, 1), &t_v);
BOOST_GEOMETRY_ASSERT( n > 0 );
// n above is unused outside BOOST_GEOMETRY_ASSERT,
// hence the call to boost::ignore_unused below
//
// however, t_v (initialized by the call to rt.query(...))
// is used below, which is why we cannot put the call to
// rt.query(...) inside BOOST_GEOMETRY_ASSERT
boost::ignore_unused(n);
Distance dist = dispatch::distance
<
RTreeValueType,
typename std::iterator_traits
<
QueryRangeIterator
>::value_type,
Strategies
>::apply(t_v, *qit, strategies);
if (first || dist < dist_min)
{
dist_min = dist;
rtree_min = t_v;
qit_min = qit;
if ( math::equals(dist_min, zero) )
{
return;
}
}
}
}
public:
template <typename RTreeRangeIterator, typename QueryRangeIterator>
struct return_type
{
typedef std::pair
<
typename std::iterator_traits<RTreeRangeIterator>::value_type,
QueryRangeIterator
> type;
};
template
<
typename RTreeRangeIterator,
typename QueryRangeIterator,
typename Strategy,
typename Distance
>
static inline typename return_type
<
RTreeRangeIterator, QueryRangeIterator
>::type apply(RTreeRangeIterator rtree_first,
RTreeRangeIterator rtree_last,
QueryRangeIterator queries_first,
QueryRangeIterator queries_last,
Strategy const& strategy,
Distance& dist_min)
{
typedef typename std::iterator_traits
<
RTreeRangeIterator
>::value_type rtree_value_type;
rtree_value_type rtree_min;
QueryRangeIterator qit_min;
apply(rtree_first, rtree_last, queries_first, queries_last,
strategy, rtree_min, qit_min, dist_min);
return std::make_pair(rtree_min, qit_min);
}
template
<
typename RTreeRangeIterator,
typename QueryRangeIterator,
typename Strategy
>
static inline typename return_type
<
RTreeRangeIterator, QueryRangeIterator
>::type apply(RTreeRangeIterator rtree_first,
RTreeRangeIterator rtree_last,
QueryRangeIterator queries_first,
QueryRangeIterator queries_last,
Strategy const& strategy)
{
typedef typename std::iterator_traits
<
RTreeRangeIterator
>::value_type rtree_value_type;
typename strategy::distance::services::return_type
<
Strategy,
typename point_type<rtree_value_type>::type,
typename point_type
<
typename std::iterator_traits
<
QueryRangeIterator
>::value_type
>::type
>::type dist_min;
return apply(rtree_first, rtree_last, queries_first, queries_last,
strategy, dist_min);
}
};
}} // namespace detail::closest_feature
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CLOSEST_FEATURE_RANGE_TO_RANGE_HPP
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,327 @@
// 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/range/size.hpp>
#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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,24 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2014.
// Modifications copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
#include <boost/geometry/algorithms/detail/distance/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_IMPLEMENTATION_HPP
@@ -0,0 +1,289 @@
// 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) 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 Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
#include <boost/geometry/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/strategies/distance/comparable.hpp>
#include <boost/geometry/strategies/distance/services.hpp>
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>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategies const& strategies)
{
return dispatch::distance
<
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_strategies_type
>::apply(geometry1,
geometry2,
comparable_strategies_type(
strategy_converter<Strategy>::get(strategy)));
}
};
template <>
struct comparable_distance<default_strategy, false>
{
template <typename Geometry1, typename Geometry2>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
using comparable_strategy_type = strategies::distance::detail::comparable
<
typename strategies::distance::services::default_strategy
<
Geometry1, Geometry2
>::type
>;
return dispatch::distance
<
Geometry1, Geometry2, comparable_strategy_type
>::apply(geometry1, geometry2, comparable_strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic
{
template
<
typename Geometry1, typename Geometry2,
typename Tag1 = typename geometry::tag<Geometry1>::type,
typename Tag2 = typename geometry::tag<Geometry2>::type
>
struct comparable_distance
{
template <typename Strategy>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::comparable_distance
<
Strategy
>::apply(geometry1, geometry2, strategy);
}
};
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
/*!
\brief \brief_calc2{comparable distance measurement} \brief_strategy
\ingroup distance
\details The free function comparable_distance does not necessarily calculate the distance,
but it calculates a distance measure such that two distances are comparable to each other.
For example: for the Cartesian coordinate system, Pythagoras is used but the square root
is not taken, which makes it faster and the results of two point pairs can still be
compared to each other.
\tparam Geometry1 first geometry type
\tparam Geometry2 second geometry type
\tparam Strategy \tparam_strategy{Distance}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{distance}
\return \return_calc{comparable distance}
\qbk{distinguish,with strategy}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline auto comparable_distance(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
return resolve_dynamic::comparable_distance
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
/*!
\brief \brief_calc2{comparable distance measurement}
\ingroup distance
\details The free function comparable_distance does not necessarily calculate the distance,
but it calculates a distance measure such that two distances are comparable to each other.
For example: for the Cartesian coordinate system, Pythagoras is used but the square root
is not taken, which makes it faster and the results of two point pairs can still be
compared to each other.
\tparam Geometry1 first geometry type
\tparam Geometry2 second geometry type
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_calc{comparable distance}
\qbk{[include reference/algorithms/comparable_distance.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline auto comparable_distance(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
return geometry::comparable_distance(geometry1, geometry2, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COMPARABLE_DISTANCE_INTERFACE_HPP
@@ -0,0 +1,80 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
template
<
typename Source,
typename Destination,
std::size_t Dimension,
std::size_t DimensionCount
>
struct indexed_to_indexed
{
static inline void apply(Source const& source, Destination& destination)
{
typedef typename coordinate_type<Destination>::type coordinate_type;
geometry::set<min_corner, Dimension>(destination,
boost::numeric_cast<coordinate_type>(
geometry::get<min_corner, Dimension>(source)));
geometry::set<max_corner, Dimension>(destination,
boost::numeric_cast<coordinate_type>(
geometry::get<max_corner, Dimension>(source)));
indexed_to_indexed
<
Source, Destination,
Dimension + 1, DimensionCount
>::apply(source, destination);
}
};
template
<
typename Source,
typename Destination,
std::size_t DimensionCount
>
struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount>
{
static inline void apply(Source const& , Destination& )
{}
};
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP
@@ -0,0 +1,74 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
// Note: extracted from "convert.hpp" to avoid circular references convert/append
#include <cstddef>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace conversion
{
// 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
{
static inline void apply(Source const& source, Destination& destination)
{
typedef typename coordinate_type<Destination>::type coordinate_type;
set<Dimension>(destination, boost::numeric_cast<coordinate_type>(get<Dimension>(source)));
point_to_point<Source, Destination, Dimension + 1, DimensionCount>::apply(source, destination);
}
};
template <typename Source, typename Destination, std::size_t DimensionCount>
struct point_to_point<Source, Destination, DimensionCount, DimensionCount>
{
static inline void apply(Source const& , Destination& )
{}
};
template <typename Source, typename Destination>
inline void convert_point_to_point(Source const& source, Destination& destination)
{
point_to_point<Source, Destination, 0, dimension<Destination>::value>::apply(source, destination);
}
}} // namespace detail::conversion
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
@@ -0,0 +1,312 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
// 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_GRAHAM_ANDREW_HPP
#define BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_GRAHAM_ANDREW_HPP
#include <cstddef>
#include <algorithm>
#include <vector>
#include <boost/range/size.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/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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace convex_hull
{
// 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)
{
bool first = true;
in_proxy.for_each_range([&](auto const& range)
{
if (boost::empty(range))
{
return;
}
// First iterate through this range
// (this two-stage approach avoids many point copies,
// because iterators are kept in memory. Because iterators are
// not persistent (in MSVC) this approach is not applicable
// for more ranges together)
auto left_it = boost::begin(range);
auto right_it = boost::begin(range);
auto it = boost::begin(range);
for (++it; it != boost::end(range); ++it)
{
if (less(*it, *left_it))
{
left_it = it;
}
if (less(*right_it, *it))
{
right_it = it;
}
}
// Then compare with earlier
if (first)
{
// First time, assign left/right
left = *left_it;
right = *right_it;
first = false;
}
else
{
// Next time, check if this range was left/right from
// the extremes already collected
if (less(*left_it, left))
{
left = *left_it;
}
if (less(right, *right_it))
{
right = *right_it;
}
}
});
}
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)
{
in_proxy.for_each_range([&](auto const& range)
{
// Put points in one of the two output sequences
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);
switch(dir)
{
case 1 : // left side
upper_points.push_back(*it);
break;
case -1 : // right side
lower_points.push_back(*it);
break;
// 0: on line most_left-most_right,
// or most_left, or most_right,
// -> all never part of hull
}
}
});
}
/*!
\brief Graham scan algorithm to calculate convex hull
*/
template <typename InputPoint>
class graham_andrew
{
typedef InputPoint point_type;
typedef typename std::vector<point_type> container_type;
class partitions
{
friend class graham_andrew;
container_type m_lower_hull;
container_type m_upper_hull;
container_type m_copied_input;
};
public:
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);
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
// This makes use of the geometry::less/greater predicates
// For the left boundary it is important that multiple points
// are sorted from bottom to top. Therefore the less predicate
// does not take the x-only template parameter (this fixes ticket #6019.
// For the right boundary it is not necessary (though also not harmful),
// because points are sorted from bottom to top in a later stage.
// For symmetry and to get often more balanced lower/upper halves
// we keep it.
point_type most_left, most_right;
geometry::less_exact<point_type, -1, Strategy> less;
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::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)
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>(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 <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,
SideStrategy const& side)
{
output.push_back(left);
for (auto const& i : input)
{
add_to_hull<Factor>(i, output, side);
}
add_to_hull<Factor>(right, output, side);
}
template <int Factor, typename SideStrategy>
static inline void add_to_hull(point_type const& p, container_type& output,
SideStrategy const& side)
{
output.push_back(p);
std::size_t output_size = output.size();
while (output_size >= 3)
{
auto rit = output.rbegin();
point_type const last = *rit++;
point_type const& last2 = *rit++;
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.
output.pop_back();
output.pop_back();
output.push_back(last);
output_size--;
}
else
{
return;
}
}
}
template <typename OutputIterator>
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);
BOOST_GEOMETRY_ASSERT(closed ? !boost::empty(second) : boost::size(second) > 1);
std::copy(++boost::rbegin(second), // skip the first Point
closed ? boost::rend(second) : --boost::rend(second), // skip the last Point if open
out);
typedef typename boost::range_size<container_type>::type size_type;
size_type const count = boost::size(first) + boost::size(second) - 1;
// count describes a closed case but comparison with min size of closed
// gives the result compatible also with open
// here core_detail::closure::minimum_ring_size<closed> could be used
if (count < 4)
{
// there should be only one missing
*out++ = *boost::begin(first);
}
}
};
}} // namespace detail::convex_hull
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_CONVEX_HULL_GRAHAM_ANDREW_HPP
@@ -0,0 +1,619 @@
// 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/range/size.hpp>
#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
+101
View File
@@ -0,0 +1,101 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014-2020.
// Modifications copyright (c) 2014-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
#include <cstddef>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/util/range.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace counting
{
template <std::size_t D>
struct other_count
{
template <typename Geometry>
static inline std::size_t apply(Geometry const&)
{
return D;
}
template <typename Geometry>
static inline std::size_t apply(Geometry const&, bool)
{
return D;
}
};
template <typename RangeCount>
struct polygon_count
{
template <typename Polygon>
static inline std::size_t apply(Polygon const& poly)
{
std::size_t n = RangeCount::apply(exterior_ring(poly));
auto const& rings = interior_rings(poly);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
n += RangeCount::apply(*it);
}
return n;
}
};
template <typename SingleCount>
struct multi_count
{
template <typename MultiGeometry>
static inline std::size_t apply(MultiGeometry const& multi)
{
std::size_t n = 0;
for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
{
n += SingleCount::apply(*it);
}
return n;
}
};
}} // namespace detail::counting
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COUNTING_HPP
@@ -0,0 +1,349 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2013-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
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
#include <cstddef>
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/within/implementation.hpp>
#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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace covered_by {
struct use_point_in_geometry
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return detail::within::covered_by_point_geometry(geometry1, geometry2, strategy);
}
};
struct use_relate
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return detail::relate::relate_impl
<
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);
}
};
}} // namespace detail::covered_by
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// P/P
template <typename Point1, typename Point2>
struct covered_by<Point1, Point2, point_tag, point_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiPoint>
struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename MultiPoint, typename Point>
struct covered_by<MultiPoint, Point, multi_point_tag, point_tag>
: public detail::within::multi_point_point
{};
template <typename MultiPoint1, typename MultiPoint2>
struct covered_by<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
: public detail::within::multi_point_multi_point
{};
// P/L
template <typename Point, typename Segment>
struct covered_by<Point, Segment, point_tag, segment_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename Linestring>
struct covered_by<Point, Linestring, point_tag, linestring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiLinestring>
struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename MultiPoint, typename Segment>
struct covered_by<MultiPoint, Segment, multi_point_tag, segment_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename Linestring>
struct covered_by<MultiPoint, Linestring, multi_point_tag, linestring_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename MultiLinestring>
struct covered_by<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag>
: public detail::within::multi_point_multi_geometry<false>
{};
// P/A
template <typename Point, typename Ring>
struct covered_by<Point, Ring, point_tag, ring_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename Polygon>
struct covered_by<Point, Polygon, point_tag, polygon_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename Point, typename MultiPolygon>
struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
: public detail::covered_by::use_point_in_geometry
{};
template <typename MultiPoint, typename Ring>
struct covered_by<MultiPoint, Ring, multi_point_tag, ring_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename Polygon>
struct covered_by<MultiPoint, Polygon, multi_point_tag, polygon_tag>
: public detail::within::multi_point_single_geometry<false>
{};
template <typename MultiPoint, typename MultiPolygon>
struct covered_by<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag>
: public detail::within::multi_point_multi_geometry<false>
{};
// L/L
template <typename Linestring1, typename Linestring2>
struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename MultiLinestring>
struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Linestring>
struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring1, typename MultiLinestring2>
struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
: public detail::covered_by::use_relate
{};
// L/A
template <typename Linestring, typename Ring>
struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Ring>
struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename Polygon>
struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename Polygon>
struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Linestring, typename MultiPolygon>
struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiLinestring, typename MultiPolygon>
struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
// A/A
template <typename Ring1, typename Ring2>
struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Ring, typename Polygon>
struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon, typename Ring>
struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon1, typename Polygon2>
struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename Ring, typename MultiPolygon>
struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon, typename Ring>
struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
: public detail::covered_by::use_relate
{};
template <typename Polygon, typename MultiPolygon>
struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon, typename Polygon>
struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
: public detail::covered_by::use_relate
{};
template <typename MultiPolygon1, typename MultiPolygon2>
struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
: public detail::covered_by::use_relate
{};
// 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
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
@@ -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
@@ -0,0 +1,261 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2013-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
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
#include <boost/geometry/algorithms/detail/within/interface.hpp>
#include <boost/geometry/algorithms/not_implemented.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
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template
<
typename Geometry1,
typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag2 = typename tag<Geometry2>::type
>
struct covered_by
: not_implemented<Tag1, Tag2>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy {
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct covered_by
{
template <typename Geometry1, typename Geometry2>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::within::check<Geometry1, Geometry2, Strategy>();
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
assert_dimension_equal<Geometry1, Geometry2>();
return dispatch::covered_by
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
};
template <typename 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 strategies::relate::services::default_strategy
<
Geometry1,
Geometry2
>::type strategy_type;
return covered_by
<
strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic {
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>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::covered_by
<
Strategy
>::apply(geometry1, geometry2, strategy);
}
};
template <typename Geometry1, typename Geometry2, typename Tag2>
struct covered_by<Geometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
bool result = false;
traits::visit<Geometry1>::apply([&](auto const& g1)
{
result = resolve_strategy::covered_by
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, typename Geometry2, typename Tag1>
struct covered_by<Geometry1, Geometry2, Tag1, dynamic_geometry_tag>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
bool result = false;
traits::visit<Geometry2>::apply([&](auto const& g2)
{
result = resolve_strategy::covered_by
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
template <typename Geometry1, typename Geometry2>
struct covered_by<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
bool result = false;
traits::visit<Geometry1, Geometry2>::apply([&](auto const& g1, auto const& g2)
{
result = resolve_strategy::covered_by
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_dynamic
/*!
\brief \brief_check12{is inside or on border}
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}.
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry which might be inside or on the border of the second geometry
\param geometry2 \param_geometry which might cover the first geometry
\return true if geometry1 is inside of or on the border of geometry2,
else false
\note The default strategy is used for covered_by detection
\qbk{[include reference/algorithms/covered_by.qbk]}
\qbk{
[heading Examples]
[covered_by]
[covered_by_output]
}
*/
template<typename Geometry1, typename Geometry2>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
{
return resolve_dynamic::covered_by
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, default_strategy());
}
/*!
\brief \brief_check12{is inside or on border} \brief_strategy
\ingroup covered_by
\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry which might be inside or on the border of the second geometry
\param geometry2 \param_geometry which might cover the first geometry
\param strategy strategy to be used
\return true if geometry1 is inside of or on the border of geometry2,
else false
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/covered_by.qbk]}
*/
template<typename Geometry1, typename Geometry2, typename Strategy>
inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_dynamic::covered_by
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
+288
View File
@@ -0,0 +1,288 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015-2020 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015-2020.
// Modifications copyright (c) 2015-2020 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
#include <type_traits>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/static_assert.hpp>
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/util/select_coordinate_type.hpp>
#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
template <typename CSTag>
struct direction_code_impl
{
BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
"Not implemented for this coordinate system.",
CSTag);
};
template <>
struct direction_code_impl<cartesian_tag>
{
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
Point2 const& point)
{
using calc_t = typename geometry::select_coordinate_type
<
PointSegmentA, PointSegmentB, Point2
>::type;
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 const sv = arithmetic::side_value(line, point);
static calc_t const zero = 0;
return sv == zero ? 0 : sv > zero ? 1 : -1;
}
};
template <>
struct direction_code_impl<spherical_equatorial_tag>
{
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA const& segment_a, PointSegmentB const& segment_b,
Point2 const& p)
{
{
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);
}
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;
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_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))) )
{
return 0;
}
// NOTE: as opposed to the implementation for cartesian CS
// here point b is the origin
calc_t const dlon1 = math::longitude_distance_signed<units_t, calc_t>(b0, a0);
calc_t const dlon2 = math::longitude_distance_signed<units_t, calc_t>(b0, p0);
bool is_antilon1 = false, is_antilon2 = false;
calc_t const dlat1 = latitude_distance_signed<units_t, calc_t>(b1, a1, dlon1, is_antilon1);
calc_t const dlat2 = latitude_distance_signed<units_t, calc_t>(b1, p1, dlon2, is_antilon2);
calc_t 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)
{
s1 = dlon1 > 0 ? 1 : -1;
s2 = dlon2 > 0 ? 1 : -1;
}
else
{
s1 = dlat1 > 0 ? 1 : -1;
s2 = dlat2 > 0 ? 1 : -1;
}
return s1 == s2 ? -1 : 1;
}
template <typename Units, typename T>
static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon)
{
using constants = math::detail::constants_on_spheroid<T, Units>;
static T const pi = constants::half_period();
static T const c0 = 0;
T res = lat2 - lat1;
is_antilon = math::equals(math::abs(lon_ds), pi);
if (is_antilon)
{
res = lat2 + lat1;
if (res >= c0)
res = pi - res;
else
res = -pi - res;
}
return res;
}
};
template <>
struct direction_code_impl<spherical_polar_tag>
{
template <typename PointSegmentA, typename PointSegmentB, typename Point2>
static inline int apply(PointSegmentA segment_a, PointSegmentB segment_b,
Point2 p)
{
using constants_sa_t = 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 cs_angular_units<Point2>::type
>;
geometry::set<1>(segment_a,
constants_sa_t::max_latitude() - geometry::get<1>(segment_a));
geometry::set<1>(segment_b,
constants_sa_t::max_latitude() - geometry::get<1>(segment_b));
geometry::set<1>(p,
constants_p_t::max_latitude() - geometry::get<1>(p));
return direction_code_impl
<
spherical_equatorial_tag
>::apply(segment_a, segment_b, p);
}
};
// if spherical_tag is passed then pick cs_tag based on 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)
// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
// Returns 1 if p goes forward, so extends (a,b)
// Returns 0 if p is equal with b, or if (a,b) is degenerate
// Note that it does not do any collinearity test, that should be done before
// 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<CSTag>::apply(segment_a, segment_b, p);
}
} // namespace detail
#endif //DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP
@@ -0,0 +1,169 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/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/geometries/helper_geometry.hpp>
#include <boost/geometry/algorithms/for_each.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool point_on_border_covered_by(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
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 Geometry1, typename Geometry2, typename Strategy>
inline bool rings_containing(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return geometry::detail::any_range_of(geometry2, [&](auto const& range)
{
return point_on_border_covered_by(range, geometry1, strategy);
});
}
template <typename Geometry1, typename Geometry2>
struct areal_areal
{
/*!
\tparam Strategy relate (segments intersection) strategy
*/
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
if ( ! disjoint_linear<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy) )
{
return false;
}
// If there is no intersection of segments, they might located
// inside each other
// We check that using a point on the border (external boundary),
// and see if that is contained in the other geometry. And vice versa.
if ( rings_containing(geometry1, geometry2, strategy)
|| rings_containing(geometry2, geometry1, strategy) )
{
return false;
}
return true;
}
};
template <typename Areal, typename Box>
struct areal_box
{
/*!
\tparam Strategy relate (segments intersection) strategy
*/
template <typename Strategy>
static inline bool apply(Areal const& areal,
Box const& box,
Strategy const& strategy)
{
if (! geometry::all_segments_of(areal, [&](auto const& s)
{
return disjoint_segment_box::apply(s, box, strategy);
}) )
{
return false;
}
// If there is no intersection of any segment and box,
// the box might be located inside areal geometry
if ( point_on_border_covered_by(box, areal, strategy) )
{
return false;
}
return true;
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Areal1, typename Areal2>
struct disjoint<Areal1, Areal2, 2, areal_tag, areal_tag, false>
: detail::disjoint::areal_areal<Areal1, Areal2>
{};
template <typename Areal, typename Box>
struct disjoint<Areal, Box, 2, areal_tag, box_tag, false>
: detail::disjoint::areal_box<Areal, Box>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_AREAL_AREAL_HPP
@@ -0,0 +1,93 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
#include <cstddef>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/strategies/detail.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
/*!
\brief Internal utility function to detect if boxes are disjoint
\note Is used from other algorithms, declared separately
to avoid circular references
*/
template
<
typename Box1, typename Box2, typename Strategy,
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);
}
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Box1, typename Box2, std::size_t DimensionCount>
struct disjoint<Box1, Box2, DimensionCount, box_tag, box_tag, false>
{
template <typename Strategy>
static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
{
typedef decltype(strategy.disjoint(box1, box2)) strategy_type;
return strategy_type::apply(box1, box2);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_BOX_BOX_HPP
@@ -0,0 +1,41 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_IMPLEMENTATION_HPP
#include <boost/geometry/algorithms/detail/disjoint/areal_areal.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_areal.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
#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
@@ -0,0 +1,238 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
#include <cstddef>
#include <boost/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/default_strategy.hpp>
#include <boost/geometry/strategies/detail.hpp>
#include <boost/geometry/strategies/relate/services.hpp>
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>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return dispatch::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 strategies::relate::services::default_strategy
<
Geometry1, Geometry2
>::type strategy_type;
return dispatch::disjoint
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic {
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)
{
concepts::check_concepts_and_equal_dimensions
<
Geometry1 const,
Geometry2 const
>();
return resolve_strategy::disjoint
<
Strategy
>::apply(geometry1, geometry2, strategy);
}
};
template <typename Geometry1, typename Geometry2>
struct disjoint<Geometry1, Geometry2, true, false>
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
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;
}
};
// 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>
static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
Strategy const& strategy)
{
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;
}
};
} // namespace resolve_dynamic
/*!
\brief \brief_check2{are disjoint}
\ingroup disjoint
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Disjoint}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{disjoint}
\return \return_check2{are disjoint}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/disjoint.qbk]}
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline bool disjoint(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_dynamic::disjoint
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, strategy);
}
/*!
\brief \brief_check2{are disjoint}
\ingroup disjoint
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_check2{are disjoint}
\qbk{[include reference/algorithms/disjoint.qbk]}
\qbk{
[heading Examples]
[disjoint]
[disjoint_output]
}
*/
template <typename Geometry1, typename Geometry2>
inline bool disjoint(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
return resolve_dynamic::disjoint
<
Geometry1, Geometry2
>::apply(geometry1, geometry2, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_INTERFACE_HPP
@@ -0,0 +1,290 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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 Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
#include <iterator>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/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/point_on_border.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/segment_box.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template <typename Geometry1, typename Geometry2,
typename Tag1 = typename tag<Geometry1>::type,
typename Tag1OrMulti = typename tag_cast<Tag1, multi_tag>::type>
struct disjoint_no_intersections_policy
{
/*!
\tparam Strategy point_in_geometry strategy
*/
template <typename Strategy>
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
{
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);
}
};
template <typename Geometry1, typename Geometry2, typename Tag1>
struct disjoint_no_intersections_policy<Geometry1, Geometry2, Tag1, multi_tag>
{
/*!
\tparam Strategy point_in_geometry strategy
*/
template <typename Strategy>
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
{
// TODO: use partition or rtree on g2
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))
{
return false;
}
}
return true;
}
};
template<typename Geometry1, typename Geometry2,
typename NoIntersectionsPolicy
= disjoint_no_intersections_policy<Geometry1, Geometry2> >
struct disjoint_linear_areal
{
/*!
\tparam Strategy relate (segments intersection) strategy
*/
template <typename Strategy>
static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
{
// if there are intersections - return false
if ( !disjoint_linear<Geometry1, Geometry2>::apply(g1, g2, strategy) )
{
return false;
}
return NoIntersectionsPolicy::apply(g1, g2, strategy);
}
};
template
<
typename Segment,
typename Areal,
typename Tag = typename tag<Areal>::type
>
struct disjoint_segment_areal
: not_implemented<Segment, Areal>
{};
template <typename Segment, typename Polygon>
class disjoint_segment_areal<Segment, Polygon, polygon_tag>
{
template <typename InteriorRings, typename Strategy>
static inline
bool check_interior_rings(InteriorRings const& interior_rings,
Segment const& segment,
Strategy const& strategy)
{
using ring_type = typename boost::range_value<InteriorRings>::type;
using unary_predicate_type = unary_disjoint_geometry_to_query_geometry
<
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));
}
public:
template <typename IntersectionStrategy>
static inline bool apply(Segment const& segment,
Polygon const& polygon,
IntersectionStrategy const& 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))
{
return false;
}
typename point_type<Segment>::type p;
detail::assign_point_from_index<0>(segment, p);
return ! geometry::covered_by(p, polygon, strategy);
}
};
template <typename Segment, typename MultiPolygon>
struct disjoint_segment_areal<Segment, MultiPolygon, multi_polygon_tag>
{
template <typename IntersectionStrategy>
static inline bool apply(Segment const& segment, MultiPolygon const& multipolygon,
IntersectionStrategy const& strategy)
{
return multirange_constant_size_geometry
<
MultiPolygon, Segment
>::apply(multipolygon, segment, strategy);
}
};
template <typename Segment, typename Ring>
struct disjoint_segment_areal<Segment, Ring, ring_tag>
{
template <typename IntersectionStrategy>
static inline bool apply(Segment const& segment,
Ring const& ring,
IntersectionStrategy const& strategy)
{
if (! disjoint_range_segment_or_box<Ring, Segment>::apply(ring, segment, strategy))
{
return false;
}
typename point_type<Segment>::type p;
detail::assign_point_from_index<0>(segment, p);
return ! geometry::covered_by(p, ring, strategy);
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Areal>
struct disjoint<Linear, Areal, 2, linear_tag, areal_tag, false>
: public detail::disjoint::disjoint_linear_areal<Linear, Areal>
{};
template <typename Areal, typename Linear>
struct disjoint<Areal, Linear, 2, areal_tag, linear_tag, false>
{
template <typename Strategy>
static inline bool apply(Areal const& areal, Linear const& linear,
Strategy const& strategy)
{
return detail::disjoint::disjoint_linear_areal
<
Linear, Areal
>::apply(linear, areal, strategy);
}
};
template <typename Areal, typename Segment>
struct disjoint<Areal, Segment, 2, areal_tag, segment_tag, false>
{
template <typename Strategy>
static inline bool apply(Areal const& g1, Segment const& g2,
Strategy const& strategy)
{
return detail::disjoint::disjoint_segment_areal
<
Segment, Areal
>::apply(g2, g1, strategy);
}
};
template <typename Segment, typename Areal>
struct disjoint<Segment, Areal, 2, segment_tag, areal_tag, false>
: detail::disjoint::disjoint_segment_areal<Segment, Areal>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_AREAL_HPP
@@ -0,0 +1,168 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-2020.
// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
#include <cstddef>
#include <deque>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp>
#include <boost/geometry/geometries/helper_geometry.hpp>
#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template <typename Segment1, typename Segment2>
struct disjoint_segment
{
template <typename Strategy>
static inline bool apply(Segment1 const& segment1, Segment2 const& segment2,
Strategy const& strategy)
{
typedef typename point_type<Segment1>::type point_type;
typedef segment_intersection_points<point_type> intersection_return_type;
typedef policies::relate::segments_intersection_points
<
intersection_return_type
> intersection_policy;
detail::segment_as_subrange<Segment1> sub_range1(segment1);
detail::segment_as_subrange<Segment2> sub_range2(segment2);
intersection_return_type is = strategy.relate().apply(sub_range1, sub_range2,
intersection_policy());
return is.count == 0;
}
};
struct assign_disjoint_policy
{
// We want to include all points:
static bool const include_no_turn = true;
static bool const include_degenerate = true;
static bool const include_opposite = true;
static bool const include_start_turn = false;
};
template <typename Geometry1, typename Geometry2>
struct disjoint_linear
{
template <typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
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
<
typename coordinate_type<point_type>::type
> ;
using turn_info_type = overlay::turn_info
<
mutable_point_type,
ratio_type,
typename detail::get_turns::turn_operation_type
<
Geometry1, Geometry2, mutable_point_type, ratio_type
>::type
>;
std::deque<turn_info_type> turns;
// Specify two policies:
// 1) Stop at any intersection
// 2) In assignment, include also degenerate points (which are normally skipped)
disjoint_interrupt_policy interrupt_policy;
dispatch::get_turns
<
typename geometry::tag<Geometry1>::type,
typename geometry::tag<Geometry2>::type,
Geometry1,
Geometry2,
overlay::do_reverse<geometry::point_order<Geometry1>::value>::value, // should be false
overlay::do_reverse<geometry::point_order<Geometry2>::value>::value, // should be false
detail::get_turns::get_turn_info_type
<
Geometry1, Geometry2, assign_disjoint_policy
>
>::apply(0, geometry1, 1, geometry2,
strategy, detail::no_rescale_policy(), turns, interrupt_policy);
return !interrupt_policy.has_intersections;
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear1, typename Linear2>
struct disjoint<Linear1, Linear2, 2, linear_tag, linear_tag, false>
: detail::disjoint::disjoint_linear<Linear1, Linear2>
{};
template <typename Segment1, typename Segment2>
struct disjoint<Segment1, Segment2, 2, segment_tag, segment_tag, false>
: detail::disjoint::disjoint_segment<Segment1, Segment2>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_LINEAR_HPP
@@ -0,0 +1,187 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
#include <boost/range/size.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/views/closeable_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template
<
typename SegmentOrBox,
typename Tag = typename tag<SegmentOrBox>::type
>
struct disjoint_point_segment_or_box
: not_implemented<Tag>
{};
template <typename Segment>
struct disjoint_point_segment_or_box<Segment, segment_tag>
{
template <typename Point, typename Strategy>
static inline bool apply(Point const& point, Segment const& segment, Strategy const& strategy)
{
return dispatch::disjoint
<
Point, Segment
>::apply(point, segment, strategy);
}
};
template <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>
static inline bool apply(Range const& range,
SegmentOrBox const& segment_or_box,
Strategy const& strategy)
{
using point_type = typename point_type<Range>::type;
using range_segment = typename geometry::model::referring_segment<point_type const>;
detail::closed_view<Range const> const view(range);
auto const count = ::boost::size(view);
if ( count == 0 )
{
return false;
}
else if ( count == 1 )
{
return disjoint_point_segment_or_box
<
SegmentOrBox
>::apply(range::front(view), segment_or_box, strategy);
}
else
{
auto it0 = ::boost::begin(view);
auto it1 = ::boost::begin(view) + 1;
auto const last = ::boost::end(view);
for ( ; it1 != last ; ++it0, ++it1 )
{
point_type const& p0 = *it0;
point_type const& p1 = *it1;
range_segment rng_segment(p0, p1);
if ( !dispatch::disjoint
<
range_segment, SegmentOrBox
>::apply(rng_segment, segment_or_box, strategy) )
{
return false;
}
}
return true;
}
}
};
template
<
typename Linear,
typename SegmentOrBox,
typename Tag = typename tag<Linear>::type
>
struct disjoint_linear_segment_or_box
: not_implemented<Linear, SegmentOrBox>
{};
template <typename Linestring, typename SegmentOrBox>
struct disjoint_linear_segment_or_box<Linestring, SegmentOrBox, linestring_tag>
: disjoint_range_segment_or_box<Linestring, SegmentOrBox>
{};
template <typename MultiLinestring, typename SegmentOrBox>
struct disjoint_linear_segment_or_box
<
MultiLinestring, SegmentOrBox, multi_linestring_tag
> : multirange_constant_size_geometry<MultiLinestring, SegmentOrBox>
{};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Segment>
struct disjoint<Linear, Segment, 2, linear_tag, segment_tag, false>
: detail::disjoint::disjoint_linear_segment_or_box<Linear, Segment>
{};
template <typename Linear, typename Box, std::size_t DimensionCount>
struct disjoint<Linear, Box, DimensionCount, linear_tag, box_tag, false>
: detail::disjoint::disjoint_linear_segment_or_box<Linear, Box>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_LINEAR_SEGMENT_OR_BOX_HPP
@@ -0,0 +1,579 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// 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
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP
#include <algorithm>
#include <vector>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/policies/compare.hpp>
// TEMP
#include <boost/geometry/strategies/envelope/cartesian.hpp>
#include <boost/geometry/strategies/envelope/geographic.hpp>
#include <boost/geometry/strategies/envelope/spherical.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
class multipoint_multipoint
{
private:
template <typename Iterator, typename Strategy>
class unary_not_disjoint_predicate
: geometry::less<void, -1, Strategy>
{
private:
using less_type = geometry::less<void, -1, Strategy>;
public:
unary_not_disjoint_predicate(Iterator first, Iterator last)
: less_type(), m_first(first), m_last(last)
{}
template <typename Point>
inline bool operator()(Point const& point) const
{
return std::binary_search(m_first,
m_last,
point,
static_cast<less_type const&>(*this));
}
private:
Iterator m_first, m_last;
};
public:
template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
static inline bool apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
Strategy const&)
{
BOOST_GEOMETRY_ASSERT( boost::size(multipoint1) <= boost::size(multipoint2) );
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(), less_type());
using predicate_type = unary_not_disjoint_predicate
<
typename std::vector<point1_type>::const_iterator,
Strategy
>;
return none_of(boost::begin(multipoint2),
boost::end(multipoint2),
predicate_type(points1.begin(), points1.end()));
}
};
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>
void apply(Box& total, Point const& point) const
{
geometry::expand(total, point, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct expand_box_segment
{
explicit expand_box_segment(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Segment>
void apply(Box& total, Segment const& segment) const
{
geometry::expand(total,
geometry::return_envelope<Box>(segment, m_strategy),
m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_point
{
explicit overlaps_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
bool apply(Box const& box, Point const& point) const
{
return ! detail::disjoint::disjoint_point_box(point, box,
m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_segment
{
explicit overlaps_box_segment(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Segment>
bool apply(Box const& box, Segment const& segment) const
{
return ! dispatch::disjoint<Segment, Box>::apply(segment, box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
class item_visitor_type
{
public:
item_visitor_type(Strategy const& strategy)
: m_intersection_found(false)
, m_strategy(strategy)
{}
template <typename Item1, typename Item2>
inline bool apply(Item1 const& item1, Item2 const& item2)
{
if (! m_intersection_found
&& ! dispatch::disjoint<Item1, Item2>::apply(item1, item2, m_strategy))
{
m_intersection_found = true;
return false;
}
return true;
}
inline bool intersection_found() const { return m_intersection_found; }
private:
bool m_intersection_found;
Strategy const& m_strategy;
};
// structs for partition -- end
class segment_range
{
public:
typedef geometry::segment_iterator<Linear const> const_iterator;
typedef const_iterator iterator;
segment_range(Linear const& linear)
: m_linear(linear)
{}
const_iterator begin() const
{
return geometry::segments_begin(m_linear);
}
const_iterator end() const
{
return geometry::segments_end(m_linear);
}
private:
Linear const& m_linear;
};
public:
template <typename Strategy>
static inline bool apply(MultiPoint const& multipoint, Linear const& linear, Strategy const& strategy)
{
item_visitor_type<Strategy> visitor(strategy);
// TODO: disjoint Segment/Box may be called in partition multiple times
// possibly for non-cartesian segments which could be slow. We should consider
// passing a range of bounding boxes of segments after calculating them once.
// Alternatively instead of a range of segments a range of Segment/Envelope pairs
// should be passed, where envelope would be lazily calculated when needed the first time
geometry::partition
<
geometry::model::box<typename point_type<MultiPoint>::type>
>::apply(multipoint, segment_range(linear), visitor,
expand_box_point<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)
{
return apply(multipoint, linear, strategy);
}
};
template <typename MultiPoint, typename SingleGeometry>
class multi_point_single_geometry
{
public:
template <typename Strategy>
static inline bool apply(MultiPoint const& multi_point,
SingleGeometry const& single_geometry,
Strategy const& strategy)
{
typedef typename 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);
geometry::detail::expand_by_epsilon(box2);
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, strategy)
&& ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy))
{
return false;
}
}
return true;
}
template <typename Strategy>
static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point,
Strategy const& strategy)
{
return apply(multi_point, single_geometry, strategy);
}
};
template <typename MultiPoint, typename MultiGeometry>
class multi_point_multi_geometry
{
private:
template <typename Strategy>
struct expand_box_point
{
explicit expand_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
void apply(Box& total, Point const& point) const
{
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>
void apply(Box& total, BoxPair const& box_pair) const
{
geometry::expand(total, box_pair.first, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_point
{
explicit overlaps_box_point(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename Point>
bool apply(Box const& box, Point const& point) const
{
return ! detail::disjoint::disjoint_point_box(point, box, m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
struct overlaps_box_box_pair
{
explicit overlaps_box_box_pair(Strategy const& strategy)
: m_strategy(strategy)
{}
template <typename Box, typename BoxPair>
bool apply(Box const& box, BoxPair const& box_pair) const
{
return ! detail::disjoint::disjoint_box_box(box_pair.first, box,
m_strategy);
}
Strategy const& m_strategy;
};
template <typename Strategy>
class item_visitor_type
{
public:
item_visitor_type(MultiGeometry const& multi_geometry,
Strategy const& strategy)
: m_intersection_found(false)
, m_multi_geometry(multi_geometry)
, m_strategy(strategy)
{}
template <typename Point, typename BoxPair>
inline bool apply(Point const& point, BoxPair const& box_pair)
{
typedef typename 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, 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;
}
return true;
}
inline bool intersection_found() const { return m_intersection_found; }
private:
bool m_intersection_found;
MultiGeometry const& m_multi_geometry;
Strategy const& m_strategy;
};
// structs for partition -- end
public:
template <typename Strategy>
static inline bool apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Strategy const& strategy)
{
typedef typename point_type<MultiPoint>::type point1_type;
typedef typename point_type<MultiGeometry>::type point2_type;
typedef model::box<point1_type> box1_type;
typedef model::box<point2_type> box2_type;
typedef std::pair<box2_type, std::size_t> box_pair_type;
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, strategy);
geometry::detail::expand_by_epsilon(boxes[i].first);
boxes[i].second = i;
}
item_visitor_type<Strategy> visitor(multi_geometry, strategy);
geometry::partition
<
box1_type
>::apply(multi_point, boxes, visitor,
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();
}
template <typename Strategy>
static inline bool apply(MultiGeometry const& multi_geometry, MultiPoint const& multi_point, Strategy const& strategy)
{
return apply(multi_point, multi_geometry, strategy);
}
};
template <typename MultiPoint, typename Areal, typename Tag = typename tag<Areal>::type>
struct multipoint_areal
: multi_point_single_geometry<MultiPoint, Areal>
{};
template <typename MultiPoint, typename Areal>
struct multipoint_areal<MultiPoint, Areal, multi_polygon_tag>
: multi_point_multi_geometry<MultiPoint, Areal>
{};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Point, typename MultiPoint, std::size_t DimensionCount>
struct disjoint
<
Point, MultiPoint, DimensionCount, point_tag, multi_point_tag, false
> : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Point>
{};
template <typename MultiPoint, typename Segment, std::size_t DimensionCount>
struct disjoint
<
MultiPoint, Segment, DimensionCount, multi_point_tag, segment_tag, false
> : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Segment>
{};
template <typename MultiPoint, typename Box, std::size_t DimensionCount>
struct disjoint
<
MultiPoint, Box, DimensionCount, multi_point_tag, box_tag, false
> : detail::disjoint::multirange_constant_size_geometry<MultiPoint, Box>
{};
template
<
typename MultiPoint1,
typename MultiPoint2,
std::size_t DimensionCount
>
struct disjoint
<
MultiPoint1, MultiPoint2, DimensionCount,
multi_point_tag, multi_point_tag, false
>
{
template <typename Strategy>
static inline bool apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
Strategy const& strategy)
{
if ( boost::size(multipoint2) < boost::size(multipoint1) )
{
return detail::disjoint::multipoint_multipoint
::apply(multipoint2, multipoint1, strategy);
}
return detail::disjoint::multipoint_multipoint
::apply(multipoint1, multipoint2, strategy);
}
};
template <typename Linear, typename MultiPoint, std::size_t DimensionCount>
struct disjoint
<
Linear, MultiPoint, DimensionCount, linear_tag, multi_point_tag, false
> : detail::disjoint::multipoint_linear<MultiPoint, Linear>
{};
template <typename MultiPoint, typename Linear, std::size_t DimensionCount>
struct disjoint
<
MultiPoint, Linear, DimensionCount, multi_point_tag, linear_tag, false
> : detail::disjoint::multipoint_linear<MultiPoint, Linear>
{};
template <typename Areal, typename MultiPoint, std::size_t DimensionCount>
struct disjoint
<
Areal, MultiPoint, DimensionCount, areal_tag, multi_point_tag, false
> : detail::disjoint::multipoint_areal<MultiPoint, Areal>
{};
template <typename MultiPoint, typename Areal, std::size_t DimensionCount>
struct disjoint
<
MultiPoint, Areal, DimensionCount, multi_point_tag, areal_tag, false
> : detail::disjoint::multipoint_areal<MultiPoint, Areal>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIPOINT_GEOMETRY_HPP
@@ -0,0 +1,96 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
#include <algorithm>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template <typename Geometry, typename Strategy, typename BinaryPredicate>
class unary_disjoint_geometry_to_query_geometry
{
public:
unary_disjoint_geometry_to_query_geometry(Geometry const& geometry,
Strategy const& strategy)
: m_geometry(geometry)
, m_strategy(strategy)
{}
template <typename QueryGeometry>
inline bool operator()(QueryGeometry const& query_geometry) const
{
return BinaryPredicate::apply(query_geometry, m_geometry, m_strategy);
}
private:
Geometry const& m_geometry;
Strategy const& m_strategy;
};
template<typename MultiRange, typename ConstantSizeGeometry>
struct multirange_constant_size_geometry
{
template <typename Strategy>
static inline bool apply(MultiRange const& multirange,
ConstantSizeGeometry const& constant_size_geometry,
Strategy const& strategy)
{
using disjoint = unary_disjoint_geometry_to_query_geometry
<
ConstantSizeGeometry,
Strategy,
dispatch::disjoint
<
typename boost::range_value<MultiRange>::type,
ConstantSizeGeometry
>
>;
return std::all_of(boost::begin(multirange),
boost::end(multirange),
disjoint(constant_size_geometry, strategy));
}
template <typename Strategy>
static inline bool apply(ConstantSizeGeometry const& constant_size_geometry,
MultiRange const& multirange,
Strategy const& strategy)
{
return apply(multirange, constant_size_geometry, strategy);
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_MULTIRANGE_GEOMETRY_HPP
@@ -0,0 +1,98 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
#include <cstddef>
#include <boost/geometry/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/strategies/detail.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
/*!
\brief Internal utility function to detect if point/box are disjoint
*/
template
<
typename Point, typename Box, typename Strategy,
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);
}
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Point, typename Box, std::size_t DimensionCount>
struct disjoint<Point, Box, DimensionCount, point_tag, box_tag, false>
{
template <typename Strategy>
static inline bool apply(Point const& point, Box const& box,
Strategy const& strategy)
{
typedef decltype(strategy.covered_by(point, box)) strategy_type;
// ! covered_by(point, box)
return ! strategy_type::apply(point, box);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_BOX_HPP
@@ -0,0 +1,89 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
#include <boost/geometry/algorithms/detail/disjoint/linear_linear.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
struct reverse_covered_by
{
template <typename Geometry1, typename Geometry2, typename Strategy>
static inline bool apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return ! geometry::covered_by(geometry1, geometry2, strategy);
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template<typename Point, typename Linear, std::size_t DimensionCount>
struct disjoint<Point, Linear, DimensionCount, point_tag, linear_tag, false>
: detail::disjoint::reverse_covered_by
{};
template <typename Point, typename Areal, std::size_t DimensionCount>
struct disjoint<Point, Areal, DimensionCount, point_tag, areal_tag, false>
: detail::disjoint::reverse_covered_by
{};
template<typename Point, typename Segment, std::size_t DimensionCount>
struct disjoint<Point, Segment, DimensionCount, point_tag, segment_tag, false>
: detail::disjoint::reverse_covered_by
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_GEOMETRY_HPP
@@ -0,0 +1,106 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland
// This file was modified by Oracle on 2013-2020.
// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
#include <cstddef>
#include <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>
#include <boost/geometry/strategies/spherical/point_in_point.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
/*!
\brief Internal utility function to detect of points are disjoint
\note To avoid circular references
*/
template
<
typename Point1, typename Point2, typename Strategy,
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);
}
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Point1, typename Point2, std::size_t DimensionCount>
struct disjoint<Point1, Point2, DimensionCount, point_tag, point_tag, false>
{
template <typename Strategy>
static inline bool apply(Point1 const& point1, Point2 const& point2,
Strategy const& strategy)
{
typedef decltype(strategy.relate(point1, point2)) strategy_type;
// ! within(point1, point2)
return ! strategy_type::apply(point1, point2);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_POINT_POINT_HPP
@@ -0,0 +1,293 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2013-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
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/radian_access.hpp>
#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
#include <boost/geometry/formulas/vertex_longitude.hpp>
#include <boost/geometry/geometries/box.hpp>
// Temporary, for envelope_segment_impl
#include <boost/geometry/strategy/spherical/envelope_segment.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace disjoint
{
template <typename CS_Tag>
struct disjoint_segment_box_sphere_or_spheroid
{
struct disjoint_info
{
enum type
{
intersect,
disjoint_no_vertex,
disjoint_vertex
};
disjoint_info(type t) : m_(t){}
operator type () const {return m_;}
type m_;
private :
//prevent automatic conversion for any other built-in types
template <typename T>
operator T () const;
};
template
<
typename Segment, typename Box,
typename AzimuthStrategy,
typename NormalizeStrategy,
typename DisjointPointBoxStrategy,
typename DisjointBoxBoxStrategy
>
static inline bool apply(Segment const& segment,
Box const& box,
AzimuthStrategy const& azimuth_strategy,
NormalizeStrategy const& normalize_strategy,
DisjointPointBoxStrategy const& disjoint_point_box_strategy,
DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
{
typedef typename point_type<Segment>::type segment_point;
segment_point vertex;
return apply(segment, box, vertex,
azimuth_strategy,
normalize_strategy,
disjoint_point_box_strategy,
disjoint_box_box_strategy) != disjoint_info::intersect;
}
template
<
typename Segment, typename Box,
typename P,
typename AzimuthStrategy,
typename NormalizeStrategy,
typename DisjointPointBoxStrategy,
typename DisjointBoxBoxStrategy
>
static inline disjoint_info apply(Segment const& segment,
Box const& box,
P& vertex,
AzimuthStrategy const& azimuth_strategy,
NormalizeStrategy const& ,
DisjointPointBoxStrategy const& disjoint_point_box_strategy,
DisjointBoxBoxStrategy const& disjoint_box_box_strategy)
{
assert_dimension_equal<Segment, Box>();
typedef typename point_type<Segment>::type segment_point_type;
segment_point_type p0, p1;
geometry::detail::assign_point_from_index<0>(segment, p0);
geometry::detail::assign_point_from_index<1>(segment, p1);
//vertex not computed here
disjoint_info disjoint_return_value = disjoint_info::disjoint_no_vertex;
// Simplest cases first
// Case 1: if box contains one of segment's endpoints then they are not disjoint
if ( ! disjoint_point_box(p0, box, disjoint_point_box_strategy)
|| ! disjoint_point_box(p1, box, disjoint_point_box_strategy) )
{
return disjoint_info::intersect;
}
// Case 2: disjoint if bounding boxes are disjoint
typedef typename coordinate_type<segment_point_type>::type CT;
segment_point_type p0_normalized;
NormalizeStrategy::apply(p0, p0_normalized);
segment_point_type p1_normalized;
NormalizeStrategy::apply(p1, p1_normalized);
CT lon1 = geometry::get_as_radian<0>(p0_normalized);
CT lat1 = geometry::get_as_radian<1>(p0_normalized);
CT lon2 = geometry::get_as_radian<0>(p1_normalized);
CT lat2 = geometry::get_as_radian<1>(p1_normalized);
if (lon1 > lon2)
{
std::swap(lon1, lon2);
std::swap(lat1, lat2);
}
geometry::model::box<segment_point_type> box_seg;
strategy::envelope::detail::envelope_segment_impl
<
CS_Tag
>::template apply<geometry::radian>(lon1, lat1,
lon2, lat2,
box_seg,
azimuth_strategy);
if (disjoint_box_box(box, box_seg, disjoint_box_box_strategy))
{
return disjoint_return_value;
}
// Case 3: test intersection by comparing angles
CT alp1, a_b0, a_b1, a_b2, a_b3;
CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box);
CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box);
CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box);
CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box);
azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1);
azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0);
azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1);
azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2);
azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3);
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 (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;
}
// Case 4: The only intersection case not covered above is when all four
// points of the box are above (below) the segment in northern (southern)
// hemisphere. Then we have to compute the vertex of the segment
CT vertex_lat;
if ((lat1 < b_lat_min && vertex_north)
|| (lat1 > b_lat_max && !vertex_north))
{
CT b_lat_below; //latitude of box closest to equator
if (vertex_north)
{
vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
b_lat_below = b_lat_min;
} else {
vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg);
b_lat_below = b_lat_max;
}
//optimization TODO: computing the spherical longitude should suffice for
// the majority of cases
CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag>
::apply(lon1, lat1,
lon2, lat2,
vertex_lat,
alp1,
azimuth_strategy);
geometry::set_from_radian<0>(vertex, vertex_lon);
geometry::set_from_radian<1>(vertex, vertex_lat);
disjoint_return_value = disjoint_info::disjoint_vertex; //vertex_computed
// Check if the vertex point is within the band defined by the
// minimum and maximum longitude of the box; if yes, then return
// false if the point is above the min latitude of the box; return
// true in all other cases
if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max
&& std::abs(vertex_lat) > std::abs(b_lat_below))
{
return disjoint_info::intersect;
}
}
return disjoint_return_value;
}
};
struct disjoint_segment_box
{
template <typename Segment, typename Box, typename Strategy>
static inline bool apply(Segment const& segment,
Box const& box,
Strategy const& strategy)
{
return strategy.disjoint(segment, box).apply(segment, box);
}
};
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Segment, typename Box, std::size_t DimensionCount>
struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
: detail::disjoint::disjoint_segment_box
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_SEGMENT_BOX_HPP
@@ -0,0 +1,55 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
#include <boost/geometry/algorithms/dispatch/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Box1, typename Box2, typename Strategies>
struct distance
<
Box1, Box2, Strategies, box_tag, box_tag,
strategy_tag_distance_box_box, false
>
{
static inline auto apply(Box1 const& box1, Box2 const& box2, Strategies const& strategies)
{
boost::ignore_unused(strategies);
return strategies.distance(box1, box2).apply(box1, box2);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_BOX_TO_BOX_HPP
@@ -0,0 +1,239 @@
// 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/range/size.hpp>
#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
@@ -0,0 +1,420 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
#include <iterator>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/geometry/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/iterators/point_iterator.hpp>
#include <boost/geometry/iterators/segment_iterator.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 distance
{
// closure of segment or box point range
template
<
typename SegmentOrBox,
typename Tag = typename tag<SegmentOrBox>::type
>
struct segment_or_box_point_range_closure
: not_implemented<SegmentOrBox>
{};
template <typename Segment>
struct segment_or_box_point_range_closure<Segment, segment_tag>
{
static const closure_selector value = closed;
};
template <typename Box>
struct segment_or_box_point_range_closure<Box, box_tag>
{
static const closure_selector value = open;
};
template
<
typename Geometry,
typename SegmentOrBox,
typename Strategies,
typename Tag = typename tag<Geometry>::type
>
class geometry_to_segment_or_box
{
private:
typedef typename point_type<SegmentOrBox>::type segment_or_box_point;
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
> point_to_point_range;
typedef detail::closest_feature::geometry_to_range geometry_to_range;
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
template
<
typename SegOrBox,
typename SegOrBoxTag = typename tag<SegOrBox>::type
>
struct assign_new_min_iterator
: not_implemented<SegOrBox>
{};
template <typename Segment>
struct assign_new_min_iterator<Segment, segment_tag>
{
template <typename Iterator>
static inline void apply(Iterator&, Iterator)
{
}
};
template <typename Box>
struct assign_new_min_iterator<Box, box_tag>
{
template <typename Iterator>
static inline void apply(Iterator& it_min, Iterator it)
{
it_min = it;
}
};
// assign the points of a segment or a box to a range
template
<
typename SegOrBox,
typename PointRange,
typename SegOrBoxTag = typename tag<SegOrBox>::type
>
struct assign_segment_or_box_points
{};
template <typename Segment, typename PointRange>
struct assign_segment_or_box_points<Segment, PointRange, segment_tag>
{
static inline void apply(Segment const& segment, PointRange& range)
{
detail::assign_point_from_index<0>(segment, range[0]);
detail::assign_point_from_index<1>(segment, range[1]);
}
};
template <typename Box, typename PointRange>
struct assign_segment_or_box_points<Box, PointRange, box_tag>
{
static inline void apply(Box const& box, PointRange& range)
{
detail::assign_box_corners_oriented<true>(box, range);
}
};
public:
typedef distance::return_t<Geometry, SegmentOrBox, Strategies> return_type;
static inline return_type apply(Geometry const& geometry,
SegmentOrBox const& segment_or_box,
Strategies const& strategies,
bool check_intersection = true)
{
typedef geometry::segment_iterator
<
Geometry const
> segment_iterator_type;
typedef assign_new_min_iterator<SegmentOrBox> assign_new_value;
if (check_intersection
&& geometry::intersects(geometry, segment_or_box, strategies))
{
return return_type(0);
}
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>
seg_or_box_points(geometry::num_points(segment_or_box));
assign_segment_or_box_points
<
SegmentOrBox,
std::vector<segment_or_box_point>
>::apply(segment_or_box, seg_or_box_points);
// consider all distances of the points in the geometry to the
// segment or box
comparable_return_type cd_min1(0);
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 (auto pit = pit_min;
pit != points_end(geometry); ++pit, first = false)
{
comparable_return_type 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)
{
cd_min1 = cd;
pit_min = pit;
assign_new_value::apply(it_min1, it_pair.first);
assign_new_value::apply(it_min2, it_pair.second);
}
}
// consider all distances of the points in the segment or box to the
// segments of the geometry
comparable_return_type cd_min2(0);
segment_iterator_type sit_min;
auto it_min = boost::const_begin(seg_or_box_points);
first = true;
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;
segment_iterator_type sit
= geometry_to_range::apply(*it,
segments_begin(geometry),
segments_end(geometry),
cstrategy,
cd);
if (first || cd < cd_min2)
{
cd_min2 = cd;
it_min = it;
sit_min = sit;
}
}
if (BOOST_GEOMETRY_CONDITION(is_comparable<strategy_type>::value))
{
return (std::min)(cd_min1, cd_min2);
}
if (cd_min1 < cd_min2)
{
return strategy.apply(*pit_min, *it_min1, *it_min2);
}
else
{
return dispatch::distance
<
segment_or_box_point,
typename std::iterator_traits
<
segment_iterator_type
>::value_type,
Strategies
>::apply(*it_min, *sit_min, strategies);
}
}
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, strategies, check_intersection);
}
};
template <typename MultiPoint, typename SegmentOrBox, typename Strategies>
class geometry_to_segment_or_box
<
MultiPoint, SegmentOrBox, Strategies, multi_point_tag
>
{
private:
typedef detail::closest_feature::geometry_to_range base_type;
typedef detail::closest_feature::geometry_to_range geometry_to_range;
typedef distance::strategy_t<MultiPoint, SegmentOrBox, Strategies> strategy_type;
public:
typedef distance::return_t<MultiPoint, SegmentOrBox, Strategies> return_type;
static inline return_type apply(MultiPoint const& multipoint,
SegmentOrBox const& segment_or_box,
Strategies const& strategies)
{
distance::creturn_t<MultiPoint, SegmentOrBox, Strategies> cd_min;
auto const it_min
= geometry_to_range::apply(segment_or_box,
boost::begin(multipoint),
boost::end(multipoint),
strategy::distance::services::get_comparable
<
strategy_type
>::apply(strategies.distance(multipoint, segment_or_box)),
cd_min);
return
is_comparable<strategy_type>::value
?
cd_min
:
dispatch::distance
<
typename point_type<MultiPoint>::type,
SegmentOrBox,
Strategies
>::apply(*it_min, segment_or_box, strategies);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Segment, typename Strategy>
struct distance
<
Linear, Segment, Strategy, linear_tag, segment_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::geometry_to_segment_or_box<Linear, Segment, Strategy>
{};
template <typename Areal, typename Segment, typename Strategy>
struct distance
<
Areal, Segment, Strategy, areal_tag, segment_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy>
{};
template <typename Segment, typename Areal, typename Strategy>
struct distance
<
Segment, Areal, Strategy, segment_tag, areal_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::geometry_to_segment_or_box<Areal, Segment, Strategy>
{};
template <typename Linear, typename Box, typename Strategy>
struct distance
<
Linear, Box, Strategy, linear_tag, box_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::geometry_to_segment_or_box
<
Linear, Box, Strategy
>
{};
template <typename Areal, typename Box, typename Strategy>
struct distance
<
Areal, Box, Strategy, areal_tag, box_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::geometry_to_segment_or_box<Areal, Box, Strategy>
{};
template <typename MultiPoint, typename Segment, typename Strategy>
struct distance
<
MultiPoint, Segment, Strategy,
multi_point_tag, segment_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::geometry_to_segment_or_box
<
MultiPoint, Segment, Strategy
>
{};
template <typename MultiPoint, typename Box, typename Strategy>
struct distance
<
MultiPoint, Box, Strategy,
multi_point_tag, box_tag,
strategy_tag_distance_point_box, false
> : detail::distance::geometry_to_segment_or_box
<
MultiPoint, Box, Strategy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_GEOMETRY_TO_SEGMENT_OR_BOX_HPP
@@ -0,0 +1,41 @@
// 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-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_DETAIL_DISTANCE_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_IMPLEMENTATION_HPP
// the implementation details
#include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp>
#include <boost/geometry/algorithms/detail/distance/multipoint_to_geometry.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_to_linear.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_or_areal_to_areal.hpp>
#include <boost/geometry/algorithms/detail/distance/linear_to_box.hpp>
#include <boost/geometry/algorithms/detail/distance/geometry_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/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
@@ -0,0 +1,353 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2014 Samuel Debionne, Grenoble, France.
// This file was modified by Oracle on 2014-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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
#include <boost/concept_check.hpp>
#include <boost/geometry/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>
// TODO: move these to algorithms
#include <boost/geometry/strategies/default_distance_result.hpp>
#include <boost/geometry/strategies/distance_result.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
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// If reversal is needed, perform it
template
<
typename Geometry1, typename Geometry2, typename Strategy,
typename Tag1, typename Tag2, typename StrategyTag
>
struct distance
<
Geometry1, Geometry2, Strategy,
Tag1, Tag2, StrategyTag,
true
>
: distance<Geometry2, Geometry1, Strategy, Tag2, Tag1, StrategyTag, false>
{
static inline auto apply(Geometry1 const& g1, Geometry2 const& g2,
Strategy const& strategy)
{
return distance
<
Geometry2, Geometry1, Strategy,
Tag2, Tag1, StrategyTag,
false
>::apply(g2, g1, strategy);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct distance
{
template <typename Geometry1, typename Geometry2>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return dispatch::distance
<
Geometry1, Geometry2, Strategy
>::apply(geometry1, geometry2, strategy);
}
};
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, false>
{
template <typename Geometry1, typename Geometry2>
static inline auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
default_strategy)
{
typedef typename strategies::distance::services::default_strategy
<
Geometry1, Geometry2
>::type strategy_type;
return dispatch::distance
<
Geometry1, Geometry2, strategy_type
>::apply(geometry1, geometry2, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic
{
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 auto apply(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
return resolve_strategy::distance
<
Strategy
>::apply(geometry1, geometry2, strategy);
}
};
template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
struct 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::distance_result<DynamicGeometry1, Geometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
{
result = resolve_strategy::distance
<
Strategy
>::apply(g1, geometry2, strategy);
}, geometry1);
return result;
}
};
template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
struct 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::distance_result<Geometry1, DynamicGeometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
{
result = resolve_strategy::distance
<
Strategy
>::apply(geometry1, g2, strategy);
}, geometry2);
return result;
}
};
template <typename DynamicGeometry1, typename DynamicGeometry2>
struct 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::distance_result<DynamicGeometry1, DynamicGeometry2, Strategy>::type;
result_t result = 0;
traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
{
result = resolve_strategy::distance
<
Strategy
>::apply(g1, g2, strategy);
}, geometry1, geometry2);
return result;
}
};
} // namespace resolve_dynamic
/*!
\brief Calculate the distance between two geometries \brief_strategy
\ingroup distance
\details
\details The free function distance calculates the distance between two geometries \brief_strategy. \details_strategy_reasons
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\tparam Strategy \tparam_strategy{Distance}
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\param strategy \param_strategy{distance}
\return \return_calc{distance}
\note The strategy can be a point-point strategy. In case of distance point-line/point-polygon
it may also be a point-segment strategy.
\qbk{distinguish,with strategy}
\qbk{
[heading Available Strategies]
\* [link geometry.reference.strategies.strategy_distance_pythagoras Pythagoras (cartesian)]
\* [link geometry.reference.strategies.strategy_distance_haversine Haversine (spherical)]
\* [link geometry.reference.strategies.strategy_distance_cross_track Cross track (spherical\, point-to-segment)]
\* [link geometry.reference.strategies.strategy_distance_projected_point Projected point (cartesian\, point-to-segment)]
\* more (currently extensions): Vincenty\, Andoyer (geographic)
}
*/
/*
Note, in case of a Compilation Error:
if you get:
- "Failed to specialize function template ..."
- "error: no matching function for call to ..."
for distance, it is probably so that there is no specialization
for return_type<...> for your strategy.
*/
template <typename Geometry1, typename Geometry2, typename Strategy>
inline auto distance(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Strategy const& strategy)
{
concepts::check<Geometry1 const>();
concepts::check<Geometry2 const>();
detail::throw_on_empty_input(geometry1);
detail::throw_on_empty_input(geometry2);
return resolve_dynamic::distance
<
Geometry1,
Geometry2
>::apply(geometry1, geometry2, strategy);
}
/*!
\brief Calculate the distance between two geometries.
\ingroup distance
\details The free function distance calculates the distance between two geometries. \details_default_strategy
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
\param geometry1 \param_geometry
\param geometry2 \param_geometry
\return \return_calc{distance}
\qbk{[include reference/algorithms/distance.qbk]}
*/
template <typename Geometry1, typename Geometry2>
inline auto distance(Geometry1 const& geometry1,
Geometry2 const& geometry2)
{
return geometry::distance(geometry1, geometry2, default_strategy());
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_INTERFACE_HPP
@@ -0,0 +1,47 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
#include <type_traits>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
// metafunction to determine is a strategy is comparable or not
template <typename Strategy>
struct is_comparable
: std::is_same
<
Strategy,
typename strategy::distance::services::comparable_type
<
Strategy
>::type
>
{};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_IS_COMPARABLE_HPP
@@ -0,0 +1,70 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
#define BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/iterators/point_iterator.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
// class to choose between point_iterator and segment_iterator
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct iterator_selector
{
typedef geometry::segment_iterator<Geometry> iterator_type;
static inline iterator_type begin(Geometry& geometry)
{
return segments_begin(geometry);
}
static inline iterator_type end(Geometry& geometry)
{
return segments_end(geometry);
}
};
template <typename MultiPoint>
struct iterator_selector<MultiPoint, multi_point_tag>
{
typedef geometry::point_iterator<MultiPoint> iterator_type;
static inline iterator_type begin(MultiPoint& multipoint)
{
return points_begin(multipoint);
}
static inline iterator_type end(MultiPoint& multipoint)
{
return points_end(multipoint);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHS_DETAIL_DISTANCE_ITERATOR_SELECTOR_HPP
@@ -0,0 +1,136 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#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>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Linear, typename Areal, typename Strategies>
struct linear_to_areal
{
typedef distance::return_t<Linear, Areal, Strategies> return_type;
static inline return_type apply(Linear const& linear,
Areal const& areal,
Strategies const& strategies)
{
if ( geometry::intersects(linear, areal, strategies) )
{
return return_type(0);
}
return linear_to_linear
<
Linear, Areal, Strategies
>::apply(linear, areal, strategies, false);
}
static inline return_type apply(Areal const& areal,
Linear const& linear,
Strategies const& strategies)
{
return apply(linear, areal, strategies);
}
};
template <typename Areal1, typename Areal2, typename Strategies>
struct areal_to_areal
{
typedef distance::return_t<Areal1, Areal2, Strategies> return_type;
static inline return_type apply(Areal1 const& areal1,
Areal2 const& areal2,
Strategies const& strategies)
{
if ( geometry::intersects(areal1, areal2, strategies) )
{
return return_type(0);
}
return linear_to_linear
<
Areal1, Areal2, Strategies
>::apply(areal1, areal2, strategies, false);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Areal, typename Strategy>
struct distance
<
Linear, Areal, Strategy,
linear_tag, areal_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::linear_to_areal
<
Linear, Areal, Strategy
>
{};
template <typename Areal, typename Linear, typename Strategy>
struct distance
<
Areal, Linear, Strategy,
areal_tag, linear_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::linear_to_areal
<
Linear, Areal, Strategy
>
{};
template <typename Areal1, typename Areal2, typename Strategy>
struct distance
<
Areal1, Areal2, Strategy,
areal_tag, areal_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::areal_to_areal
<
Areal1, Areal2, Strategy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_OR_AREAL_TO_AREAL_HPP
@@ -0,0 +1,126 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Linear, typename Box, typename Strategies>
struct linear_to_box
{
typedef distance::return_t<Linear, Box, Strategies> return_type;
template <typename Iterator>
static inline return_type apply(Box const& box,
Iterator begin,
Iterator end,
Strategies const& strategies)
{
bool first = true;
return_type d_min(0);
for (Iterator it = begin; it != end; ++it, first = false)
{
typedef typename std::iterator_traits<Iterator>::value_type
Segment;
return_type d = dispatch::distance<Segment, Box, Strategies>
::apply(*it, box, strategies);
if ( first || d < d_min )
{
d_min = d;
}
}
return d_min;
}
static inline return_type apply(Linear const& linear,
Box const& box,
Strategies const& strategies)
{
if ( geometry::intersects(linear, box) )
{
return return_type(0);
}
return apply(box,
geometry::segments_begin(linear),
geometry::segments_end(linear),
strategies);
}
static inline return_type apply(Box const& box,
Linear const& linear,
Strategies const& strategies)
{
return apply(linear, box, strategies);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear, typename Box, typename Strategy>
struct distance
<
Linear, Box, Strategy,
linear_tag, box_tag,
strategy_tag_distance_segment_box, false
>
: detail::distance::linear_to_box
<
Linear, Box, Strategy
>
{};
template <typename Areal, typename Box, typename Strategy>
struct distance
<
Areal, Box, Strategy,
areal_tag, box_tag,
strategy_tag_distance_segment_box, false
>
: detail::distance::linear_to_box
<
Areal, Box, Strategy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_BOX_HPP
@@ -0,0 +1,118 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_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/core/point_type.hpp>
#include <boost/geometry/iterators/point_iterator.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/geometry/strategies/distance.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Linear1, typename Linear2, typename Strategies>
struct linear_to_linear
{
typedef distance::return_t<Linear1, Linear2, Strategies> return_type;
static inline return_type apply(Linear1 const& linear1,
Linear2 const& linear2,
Strategies const& strategies,
bool = false)
{
if (geometry::num_points(linear1) == 1)
{
return dispatch::distance
<
typename point_type<Linear1>::type,
Linear2,
Strategies
>::apply(*points_begin(linear1), linear2, strategies);
}
if (geometry::num_points(linear2) == 1)
{
return dispatch::distance
<
typename point_type<Linear2>::type,
Linear1,
Strategies
>::apply(*points_begin(linear2), linear1, strategies);
}
if (geometry::num_segments(linear2) < geometry::num_segments(linear1))
{
return point_or_segment_range_to_geometry_rtree
<
geometry::segment_iterator<Linear2 const>,
Linear1,
Strategies
>::apply(geometry::segments_begin(linear2),
geometry::segments_end(linear2),
linear1,
strategies);
}
return point_or_segment_range_to_geometry_rtree
<
geometry::segment_iterator<Linear1 const>,
Linear2,
Strategies
>::apply(geometry::segments_begin(linear1),
geometry::segments_end(linear1),
linear2,
strategies);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linear1, typename Linear2, typename Strategy, typename StrategyTag>
struct distance
<
Linear1, Linear2, Strategy,
linear_tag, linear_tag,
StrategyTag, false
> : detail::distance::linear_to_linear
<
Linear1, Linear2, Strategy
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_LINEAR_TO_LINEAR_HPP
@@ -0,0 +1,221 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/geometry/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>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename MultiPoint1, typename MultiPoint2, typename Strategies>
struct multipoint_to_multipoint
{
typedef distance::return_t<MultiPoint1, MultiPoint2, Strategies> return_type;
static inline return_type apply(MultiPoint1 const& multipoint1,
MultiPoint2 const& multipoint2,
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,
Strategies
>::apply(boost::begin(multipoint2),
boost::end(multipoint2),
multipoint1,
strategies);
}
return point_or_segment_range_to_geometry_rtree
<
typename boost::range_iterator<MultiPoint1 const>::type,
MultiPoint2,
Strategies
>::apply(boost::begin(multipoint1),
boost::end(multipoint1),
multipoint2,
strategies);
}
};
template <typename MultiPoint, typename Linear, typename Strategies>
struct multipoint_to_linear
{
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,
Strategies
>::apply(boost::begin(multipoint),
boost::end(multipoint),
linear,
strategies);
}
static inline auto apply(Linear const& linear,
MultiPoint const& multipoint,
Strategies const& strategies)
{
return apply(multipoint, linear, strategies);
}
};
template <typename MultiPoint, typename Areal, typename Strategies>
class multipoint_to_areal
{
private:
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:
typedef distance::return_t<MultiPoint, Areal, Strategies> return_type;
static inline return_type apply(MultiPoint const& multipoint,
Areal const& areal,
Strategies const& strategies)
{
covered_by_areal predicate(areal, strategies);
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,
Strategies
>::apply(boost::begin(multipoint),
boost::end(multipoint),
areal,
strategies);
}
return return_type(0);
}
static inline return_type apply(Areal const& areal,
MultiPoint const& multipoint,
Strategies const& strategies)
{
return apply(multipoint, areal, strategies);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
struct distance
<
MultiPoint1, MultiPoint2, Strategy,
multi_point_tag, multi_point_tag,
strategy_tag_distance_point_point, false
> : detail::distance::multipoint_to_multipoint
<
MultiPoint1, MultiPoint2, Strategy
>
{};
template <typename MultiPoint, typename Linear, typename Strategy>
struct distance
<
MultiPoint, Linear, Strategy, multi_point_tag, linear_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy>
{};
template <typename Linear, typename MultiPoint, typename Strategy>
struct distance
<
Linear, MultiPoint, Strategy, linear_tag, multi_point_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::multipoint_to_linear<MultiPoint, Linear, Strategy>
{};
template <typename MultiPoint, typename Areal, typename Strategy>
struct distance
<
MultiPoint, Areal, Strategy, multi_point_tag, areal_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy>
{};
template <typename Areal, typename MultiPoint, typename Strategy>
struct distance
<
Areal, MultiPoint, Strategy, areal_tag, multi_point_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::multipoint_to_areal<MultiPoint, Areal, Strategy>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_MULTIPOINT_TO_GEOMETRY_HPP
@@ -0,0 +1,539 @@
// 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-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.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
#include <iterator>
#include <type_traits>
#include <boost/core/ignore_unused.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/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>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/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 distance
{
template
<
typename P1, typename P2, typename Strategies,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
>
struct point_to_point
{
static inline
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);
}
};
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 Strategies
>
class point_to_range
{
private:
typedef distance::strategy_t<Point, Range, Strategies> strategy_type;
typedef detail::closest_feature::point_to_point_range
<
Point, Range, Closure
> point_to_point_range;
public:
typedef distance::return_t<Point, Range, Strategies> return_type;
static inline return_type apply(Point const& point, Range const& range,
Strategies const& strategies)
{
if (boost::size(range) == 0)
{
return return_type(0);
}
distance::creturn_t<Point, Range, Strategies> cd_min;
std::pair
<
typename boost::range_iterator<Range const>::type,
typename boost::range_iterator<Range const>::type
> it_pair
= point_to_point_range::apply(point,
boost::begin(range),
boost::end(range),
strategy::distance::services::get_comparable
<
strategy_type
>::apply(strategies.distance(point, range)),
cd_min);
return
is_comparable<strategy_type>::value
?
cd_min
:
strategies.distance(point, range).apply(point, *it_pair.first, *it_pair.second);
}
};
template
<
typename Point,
typename Ring,
closure_selector Closure,
typename Strategies
>
struct point_to_ring
{
typedef distance::return_t<Point, Ring, Strategies> return_type;
static inline return_type apply(Point const& point,
Ring const& ring,
Strategies const& strategies)
{
if (within::within_point_geometry(point, ring, strategies))
{
return return_type(0);
}
return point_to_range
<
Point, Ring, closure<Ring>::value, Strategies
>::apply(point, ring, strategies);
}
};
template
<
typename Point,
typename Polygon,
closure_selector Closure,
typename Strategies
>
class point_to_polygon
{
public:
typedef distance::return_t<Point, Polygon, Strategies> return_type;
private:
typedef point_to_range
<
Point, typename ring_type<Polygon>::type, Closure, Strategies
> per_ring;
struct distance_to_interior_rings
{
template <typename InteriorRingIterator>
static inline return_type apply(Point const& point,
InteriorRingIterator first,
InteriorRingIterator last,
Strategies const& strategies)
{
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 its distance to the polygon's
// hole boundary
return per_ring::apply(point, *it, strategies);
}
}
return return_type(0);
}
template <typename InteriorRings>
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),
strategies);
}
};
public:
static inline return_type apply(Point const& point,
Polygon const& polygon,
Strategies const& strategies)
{
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), strategies);
}
// Check interior rings
return distance_to_interior_rings::apply(point,
interior_rings(polygon),
strategies);
}
};
template
<
typename Point,
typename MultiGeometry,
typename Strategies,
bool CheckCoveredBy = std::is_same
<
typename tag<MultiGeometry>::type, multi_polygon_tag
>::value
>
class point_to_multigeometry
{
private:
typedef detail::closest_feature::geometry_to_range geometry_to_range;
typedef distance::strategy_t<Point, MultiGeometry, Strategies> strategy_type;
public:
typedef distance::return_t<Point, MultiGeometry, Strategies> return_type;
static inline return_type apply(Point const& point,
MultiGeometry const& multigeometry,
Strategies const& strategies)
{
typedef iterator_selector<MultiGeometry const> selector_type;
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),
strategy::distance::services::get_comparable
<
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_type>::value
?
cd
:
dispatch::distance
<
Point,
typename std::iterator_traits
<
typename selector_type::iterator_type
>::value_type,
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 Strategies>
struct point_to_multigeometry<Point, MultiPolygon, Strategies, true>
{
typedef distance::return_t<Point, MultiPolygon, Strategies> return_type;
static inline return_type apply(Point const& point,
MultiPolygon const& multipolygon,
Strategies const& strategies)
{
if (within::covered_by_point_geometry(point, multipolygon, strategies))
{
return return_type(0);
}
return point_to_multigeometry
<
Point, MultiPolygon, Strategies, false
>::apply(point, multipolygon, strategies);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename P1, typename P2, typename Strategy>
struct distance
<
P1, P2, Strategy, point_tag, point_tag,
strategy_tag_distance_point_point, false
> : detail::distance::point_to_point<P1, P2, Strategy>
{};
template <typename Point, typename Linestring, typename Strategy>
struct distance
<
Point, Linestring, Strategy, point_tag, linestring_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_range<Point, Linestring, closed, Strategy>
{};
template <typename Point, typename Ring, typename Strategy>
struct distance
<
Point, Ring, Strategy, point_tag, ring_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_ring
<
Point, Ring, closure<Ring>::value, Strategy
>
{};
template <typename Point, typename Polygon, typename Strategy>
struct distance
<
Point, Polygon, Strategy, point_tag, polygon_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_polygon
<
Point, Polygon, closure<Polygon>::value, Strategy
>
{};
template <typename Point, typename Segment, typename Strategy>
struct distance
<
Point, Segment, Strategy, point_tag, segment_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_segment<Point, Segment, Strategy>
{};
template <typename Point, typename Box, typename Strategy>
struct distance
<
Point, Box, Strategy, point_tag, box_tag,
strategy_tag_distance_point_box, false
> : detail::distance::point_to_box<Point, Box, Strategy>
{};
template<typename Point, typename MultiPoint, typename Strategy>
struct distance
<
Point, MultiPoint, Strategy, point_tag, multi_point_tag,
strategy_tag_distance_point_point, false
> : detail::distance::point_to_multigeometry
<
Point, MultiPoint, Strategy
>
{};
template<typename Point, typename MultiLinestring, typename Strategy>
struct distance
<
Point, MultiLinestring, Strategy, point_tag, multi_linestring_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_multigeometry
<
Point, MultiLinestring, Strategy
>
{};
template<typename Point, typename MultiPolygon, typename Strategy>
struct distance
<
Point, MultiPolygon, Strategy, point_tag, multi_polygon_tag,
strategy_tag_distance_point_segment, false
> : detail::distance::point_to_multigeometry
<
Point, MultiPolygon, Strategy
>
{};
template <typename Point, typename Linear, typename Strategy>
struct distance
<
Point, Linear, Strategy, point_tag, linear_tag,
strategy_tag_distance_point_segment, false
> : distance
<
Point, Linear, Strategy,
point_tag, typename tag<Linear>::type,
strategy_tag_distance_point_segment, false
>
{};
template <typename Point, typename Areal, typename Strategy>
struct distance
<
Point, Areal, Strategy, point_tag, areal_tag,
strategy_tag_distance_point_segment, false
> : distance
<
Point, Areal, Strategy,
point_tag, typename tag<Areal>::type,
strategy_tag_distance_point_segment, false
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_POINT_TO_GEOMETRY_HPP
@@ -0,0 +1,117 @@
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
#include <iterator>
#include <utility>
#include <boost/geometry/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
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template
<
typename PointOrSegmentIterator,
typename Geometry,
typename Strategies
>
class point_or_segment_range_to_geometry_rtree
{
private:
typedef typename std::iterator_traits
<
PointOrSegmentIterator
>::value_type point_or_segment_type;
typedef iterator_selector<Geometry const> selector_type;
typedef detail::closest_feature::range_to_range_rtree range_to_range;
typedef distance::strategy_t<point_or_segment_type, Geometry, Strategies> strategy_type;
public:
typedef distance::return_t<point_or_segment_type, Geometry, Strategies> return_type;
static inline return_type apply(PointOrSegmentIterator first,
PointOrSegmentIterator last,
Geometry const& geometry,
Strategies const& strategies)
{
BOOST_GEOMETRY_ASSERT( first != last );
if ( detail::has_one_element(first, last) )
{
return dispatch::distance
<
point_or_segment_type, Geometry, Strategies
>::apply(*first, geometry, strategies);
}
distance::creturn_t<point_or_segment_type, Geometry, Strategies> cd_min;
std::pair
<
point_or_segment_type,
typename selector_type::iterator_type
> closest_features
= range_to_range::apply(first,
last,
selector_type::begin(geometry),
selector_type::end(geometry),
strategies,
cd_min);
return
is_comparable<strategy_type>::value
?
cd_min
:
dispatch::distance
<
point_or_segment_type,
typename std::iterator_traits
<
typename selector_type::iterator_type
>::value_type,
Strategies
>::apply(closest_features.first,
*closest_features.second,
strategies);
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_RANGE_TO_GEOMETRY_RTREE_HPP
@@ -0,0 +1,825 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
#include <cstddef>
#include <functional>
#include <type_traits>
#include <vector>
#include <boost/core/ignore_unused.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/geometry/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>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/util/calculation_type.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/has_nan_coordinate.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/strategies/disjoint.hpp>
#include <boost/geometry/strategies/distance.hpp>
#include <boost/geometry/strategies/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace distance
{
template <typename Segment, typename Box, typename Strategy>
inline bool intersects_segment_box(Segment const& segment, Box const& box,
Strategy const& strategy)
{
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 Strategies,
bool UsePointBoxStrategy = false // use only PointSegment strategy
>
class segment_to_box_2D_generic
{
private:
typedef typename point_type<Segment>::type segment_point;
typedef typename point_type<Box>::type box_point;
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
> point_to_point_range;
public:
// 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,
Strategies const& strategies,
bool check_intersection = true)
{
if (check_intersection && intersects_segment_box(segment, box, strategies))
{
return return_type(0);
}
// get segment points
segment_point p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
// get box points
std::vector<box_point> box_points(4);
detail::assign_box_corners_oriented<true>(box, box_points);
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]);
}
std::pair
<
typename std::vector<box_point>::const_iterator,
typename std::vector<box_point>::const_iterator
> bit_min[2];
bit_min[0] = point_to_point_range::apply(p[0],
box_points.begin(),
box_points.end(),
cstrategy,
cd[4]);
bit_min[1] = point_to_point_range::apply(p[1],
box_points.begin(),
box_points.end(),
cstrategy,
cd[5]);
unsigned int imin = 0;
for (unsigned int i = 1; i < 6; ++i)
{
if (cd[i] < cd[imin])
{
imin = i;
}
}
if (BOOST_GEOMETRY_CONDITION(is_comparable<ps_strategy_type>::value))
{
return cd[imin];
}
if (imin < 4)
{
return strategy.apply(box_points[imin], p[0], p[1]);
}
else
{
unsigned int bimin = imin - 4;
return strategy.apply(p[bimin],
*bit_min[bimin].first,
*bit_min[bimin].second);
}
}
};
template
<
typename Segment,
typename Box,
typename Strategies
>
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 distance::strategy_t<box_point, Segment, Strategies> ps_strategy_type;
typedef distance::strategy_t<segment_point, Box, Strategies> pb_strategy_type;
public:
// 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,
Strategies const& strategies,
bool check_intersection = true)
{
if (check_intersection && intersects_segment_box(segment, box, strategies))
{
return return_type(0);
}
// get segment points
segment_point p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
// get box points
std::vector<box_point> box_points(4);
detail::assign_box_corners_oriented<true>(box, box_points);
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] = ps_cstrategy.apply(box_points[i], p[0], p[1]);
}
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);
unsigned int imin = 0;
for (unsigned int i = 1; i < 6; ++i)
{
if (cd[i] < cd[imin])
{
imin = i;
}
}
if (imin < 4)
{
if (is_comparable<ps_strategy_type>::value)
{
return cd[imin];
}
return ps_strategy.apply(box_points[imin], p[0], p[1]);
}
else
{
if (is_comparable<pb_strategy_type>::value)
{
return cd[imin];
}
return pb_strategy.apply(p[imin - 4], box);
}
}
};
template
<
typename ReturnType,
typename SegmentPoint,
typename BoxPoint,
typename Strategies
>
class segment_to_box_2D
{
private:
template <typename Result>
struct cast_to_result
{
template <typename T>
static inline Result apply(T const& t)
{
return boost::numeric_cast<Result>(t);
}
};
template <typename T, bool IsLess /* true */>
struct compare_less_equal
{
typedef compare_less_equal<T, !IsLess> other;
template <typename T1, typename T2>
inline bool operator()(T1 const& t1, T2 const& t2) const
{
return std::less_equal<T>()(cast_to_result<T>::apply(t1),
cast_to_result<T>::apply(t2));
}
};
template <typename T>
struct compare_less_equal<T, false>
{
typedef compare_less_equal<T, true> other;
template <typename T1, typename T2>
inline bool operator()(T1 const& t1, T2 const& t2) const
{
return std::greater_equal<T>()(cast_to_result<T>::apply(t1),
cast_to_result<T>::apply(t2));
}
};
template <typename LessEqual>
struct other_compare
{
typedef typename LessEqual::other type;
};
// it is assumed here that p0 lies to the right of the box (so the
// entire segment lies to the right of the box)
template <typename LessEqual>
struct right_of_box
{
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& bottom_right,
BoxPoint const& top_right,
Strategies const& strategies)
{
// the implementation below is written for non-negative slope
// segments
//
// for negative slope segments swap the roles of bottom_right
// and top_right and use greater_equal instead of less_equal.
typedef cast_to_result<ReturnType> cast;
LessEqual less_equal;
auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
if (less_equal(geometry::get<1>(bottom_right), geometry::get<1>(p0)))
{
//if p0 is in box's band
if (less_equal(geometry::get<1>(p0), geometry::get<1>(top_right)))
{
// segment & crosses band (TODO:merge with box-box dist)
if (math::equals(geometry::get<0>(p0), geometry::get<0>(p1)))
{
SegmentPoint high = geometry::get<1>(p1) > geometry::get<1>(p0) ? p1 : p0;
if (less_equal(geometry::get<1>(high), geometry::get<1>(top_right)))
{
return cast::apply(ps_strategy.apply(high, bottom_right, top_right));
}
return cast::apply(ps_strategy.apply(top_right, p0, p1));
}
return cast::apply(ps_strategy.apply(p0, bottom_right, top_right));
}
// distance is realized between the top-right
// corner of the box and the segment
return cast::apply(ps_strategy.apply(top_right, p0, p1));
}
else
{
// distance is realized between the bottom-right
// corner of the box and the segment
return cast::apply(ps_strategy.apply(bottom_right, p0, p1));
}
}
};
// it is assumed here that p0 lies above the box (so the
// entire segment lies above the box)
template <typename LessEqual>
struct above_of_box
{
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
Strategies const& strategies)
{
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,
Strategies const& strategies)
{
auto const ps_strategy = strategies.distance(dummy_point(), dummy_segment());
typedef cast_to_result<ReturnType> cast;
LessEqual less_equal;
// p0 is above the upper segment of the box (and inside its band)
// then compute the vertical (i.e. meridian for spherical) distance
if (less_equal(geometry::get<0>(top_left), geometry::get<0>(p_max)))
{
ReturnType diff = 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
<
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(ps_strategy.apply(top_left, p0, p1));
}
};
template <typename LessEqual>
struct check_right_left_of_box
{
static inline bool apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
Strategies const& strategies,
ReturnType& result)
{
// p0 lies to the right of the box
if (geometry::get<0>(p0) >= geometry::get<0>(top_right))
{
result = right_of_box
<
LessEqual
>::apply(p0, p1, bottom_right, top_right,
strategies);
return true;
}
// p1 lies to the left of the box
if (geometry::get<0>(p1) <= geometry::get<0>(bottom_left))
{
result = right_of_box
<
typename other_compare<LessEqual>::type
>::apply(p1, p0, top_left, bottom_left,
strategies);
return true;
}
return false;
}
};
template <typename LessEqual>
struct check_above_below_of_box
{
static inline bool apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
Strategies const& strategies,
ReturnType& result)
{
typedef compare_less_equal<ReturnType, false> GreaterEqual;
// the segment lies below the box
if (geometry::get<1>(p1) < geometry::get<1>(bottom_left))
{
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,
strategies);
return true;
}
// the segment lies above the box
if (geometry::get<1>(p0) > geometry::get<1>(top_right))
{
result = (std::min)(above_of_box
<
LessEqual
>::apply(p0, p1, top_left, strategies),
above_of_box
<
GreaterEqual
>::apply(p1, p0, top_right, strategies));
return true;
}
return false;
}
};
struct check_generic_position
{
static inline bool apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& corner1,
BoxPoint const& corner2,
Strategies const& strategies,
ReturnType& result)
{
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));
int sign = diff1 < 0 ? -1 : 1;
if (side_strategy.apply(p0, p1, corner1) * sign < 0)
{
result = cast::apply(ps_strategy.apply(corner1, p0, p1));
return true;
}
if (side_strategy.apply(p0, p1, corner2) * sign > 0)
{
result = cast::apply(ps_strategy.apply(corner2, p0, p1));
return true;
}
return false;
}
};
static inline ReturnType
non_negative_slope_segment(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
Strategies const& strategies)
{
typedef compare_less_equal<ReturnType, true> less_equal;
// assert that the segment has non-negative slope
BOOST_GEOMETRY_ASSERT( ( math::equals(geometry::get<0>(p0), geometry::get<0>(p1))
&& geometry::get<1>(p0) < geometry::get<1>(p1))
||
( geometry::get<0>(p0) < geometry::get<0>(p1)
&& geometry::get<1>(p0) <= geometry::get<1>(p1) )
|| geometry::has_nan_coordinate(p0)
|| geometry::has_nan_coordinate(p1));
ReturnType result(0);
if (check_right_left_of_box
<
less_equal
>::apply(p0, p1,
top_left, top_right, bottom_left, bottom_right,
strategies, result))
{
return result;
}
if (check_above_below_of_box
<
less_equal
>::apply(p0, p1,
top_left, top_right, bottom_left, bottom_right,
strategies, result))
{
return result;
}
if (check_generic_position::apply(p0, p1,
top_left, bottom_right,
strategies, result))
{
return result;
}
// in all other cases the box and segment intersect, so return 0
return result;
}
static inline ReturnType
negative_slope_segment(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
Strategies const& strategies)
{
typedef compare_less_equal<ReturnType, false> greater_equal;
// assert that the segment has negative slope
BOOST_GEOMETRY_ASSERT( ( geometry::get<0>(p0) < geometry::get<0>(p1)
&& geometry::get<1>(p0) > geometry::get<1>(p1) )
|| geometry::has_nan_coordinate(p0)
|| geometry::has_nan_coordinate(p1) );
ReturnType result(0);
if (check_right_left_of_box
<
greater_equal
>::apply(p0, p1,
bottom_left, bottom_right, top_left, top_right,
strategies, result))
{
return result;
}
if (check_above_below_of_box
<
greater_equal
>::apply(p1, p0,
top_right, top_left, bottom_right, bottom_left,
strategies, result))
{
return result;
}
if (check_generic_position::apply(p0, p1,
bottom_left, top_right,
strategies, result))
{
return result;
}
// in all other cases the box and segment intersect, so return 0
return result;
}
public:
static inline ReturnType apply(SegmentPoint const& p0,
SegmentPoint const& p1,
BoxPoint const& top_left,
BoxPoint const& top_right,
BoxPoint const& bottom_left,
BoxPoint const& bottom_right,
Strategies const& strategies)
{
BOOST_GEOMETRY_ASSERT( (geometry::less<SegmentPoint, -1, Strategies>()(p0, p1))
|| geometry::has_nan_coordinate(p0)
|| geometry::has_nan_coordinate(p1) );
if (geometry::get<0>(p0) < geometry::get<0>(p1)
&& geometry::get<1>(p0) > geometry::get<1>(p1))
{
return negative_slope_segment(p0, p1,
top_left, top_right,
bottom_left, bottom_right,
strategies);
}
return non_negative_slope_segment(p0, p1,
top_left, top_right,
bottom_left, bottom_right,
strategies);
}
template <typename LessEqual>
static inline ReturnType call_above_of_box(SegmentPoint const& p0,
SegmentPoint const& p1,
SegmentPoint const& p_max,
BoxPoint const& top_left,
Strategies const& strategies)
{
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,
Strategies const& strategies)
{
return above_of_box<LessEqual>::apply(p0, p1, top_left, strategies);
}
};
//=========================================================================
template
<
typename Segment,
typename Box,
typename std::size_t Dimension,
typename Strategies
>
class segment_to_box
: not_implemented<Segment, Box>
{};
template
<
typename Segment,
typename Box,
typename Strategies
>
class segment_to_box<Segment, Box, 2, Strategies>
{
typedef distance::strategy_t<Segment, Box, Strategies> strategy_type;
public:
typedef distance::return_t<Segment, Box, Strategies> return_type;
static inline return_type apply(Segment const& segment,
Box const& box,
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], strategies))
{
return dispatch::distance
<
segment_point,
Box,
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);
strategy_type::mirror(p[0], p[1],
bottom_left, bottom_right,
top_left, top_right);
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,
Strategies
>::apply(p[0], p[1],
top_left, top_right, bottom_left, bottom_right,
strategies);
}
else
{
return segment_to_box_2D
<
return_type,
segment_point,
box_point,
Strategies
>::apply(p[1], p[0],
top_left, top_right, bottom_left, bottom_right,
strategies);
}
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Segment, typename Box, typename Strategies>
struct distance
<
Segment, Box, Strategies, segment_tag, box_tag,
strategy_tag_distance_segment_box, false
>
{
static inline auto apply(Segment const& segment, Box const& box,
Strategies const& strategies)
{
assert_dimension_equal<Segment, Box>();
return detail::distance::segment_to_box
<
Segment,
Box,
dimension<Segment>::value,
Strategies
>::apply(segment, box, strategies);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_BOX_HPP
@@ -0,0 +1,136 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// 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
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
#include <algorithm>
#include <iterator>
#include <boost/core/addressof.hpp>
#include <boost/geometry/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/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 distance
{
// compute segment-segment distance
template<typename Segment1, typename Segment2, typename Strategies>
class segment_to_segment
{
typedef distance::strategy_t<Segment1, Segment2, Strategies> strategy_type;
public:
typedef distance::return_t<Segment1, Segment2, Strategies> return_type;
static inline return_type apply(Segment1 const& segment1, Segment2 const& segment2,
Strategies const& strategies)
{
if (geometry::intersects(segment1, segment2, strategies))
{
return 0;
}
typename point_type<Segment1>::type p[2];
detail::assign_point_from_index<0>(segment1, p[0]);
detail::assign_point_from_index<1>(segment1, p[1]);
typename point_type<Segment2>::type q[2];
detail::assign_point_from_index<0>(segment2, q[0]);
detail::assign_point_from_index<1>(segment2, q[1]);
strategy_type const strategy = strategies.distance(segment1, segment2);
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]);
d[3] = cstrategy.apply(p[1], q[0], q[1]);
std::size_t imin = std::distance(boost::addressof(d[0]),
std::min_element(d, d + 4));
if (BOOST_GEOMETRY_CONDITION(is_comparable<strategy_type>::value))
{
return d[imin];
}
switch (imin)
{
case 0:
return strategy.apply(q[0], p[0], p[1]);
case 1:
return strategy.apply(q[1], p[0], p[1]);
case 2:
return strategy.apply(p[0], q[0], q[1]);
default:
return strategy.apply(p[1], q[0], q[1]);
}
}
};
}} // namespace detail::distance
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// segment-segment
template <typename Segment1, typename Segment2, typename Strategy>
struct distance
<
Segment1, Segment2, Strategy, segment_tag, segment_tag,
strategy_tag_distance_point_segment, false
>
: detail::distance::segment_to_segment<Segment1, Segment2, Strategy>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISTANCE_SEGMENT_TO_SEGMENT_HPP
@@ -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
@@ -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
+113
View File
@@ -0,0 +1,113 @@
// Boost.Geometry
// 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
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/iterators/segment_iterator.hpp>
#include <boost/geometry/algorithms/detail/envelope/range.hpp>
#include <boost/geometry/algorithms/detail/envelope/linear.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/views/reversible_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
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>
static inline void apply(Polygon const& polygon, Box& mbr, Strategy const& strategy)
{
typename ring_return_type<Polygon const>::type ext_ring
= exterior_ring(polygon);
if (geometry::is_empty(ext_ring))
{
// 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_hole
>::template apply<strategy_t>(interior_rings(polygon), mbr, strategy);
}
else
{
// otherwise, consider only the exterior ring
envelope_range::apply(ext_ring, mbr, strategy);
}
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Ring>
struct envelope<Ring, ring_tag>
: detail::envelope::envelope_range
{};
template <typename Polygon>
struct envelope<Polygon, polygon_tag>
: detail::envelope::envelope_polygon
{};
template <typename MultiPolygon>
struct envelope<MultiPolygon, multi_polygon_tag>
: detail::envelope::envelope_multi_range
<
detail::envelope::envelope_polygon
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_AREAL_HPP
+53
View File
@@ -0,0 +1,53 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-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
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
#include <boost/geometry/core/tags.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Box>
struct envelope<Box, box_tag>
{
template<typename BoxIn, typename BoxOut, typename Strategy>
static inline void apply(BoxIn const& box_in, BoxOut& mbr, Strategy const& strategy)
{
using strategy_t = decltype(strategy.envelope(box_in, mbr));
strategy_t::apply(box_in, mbr);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_BOX_HPP
@@ -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
@@ -0,0 +1,44 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-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.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_IMPLEMENTATION_HPP
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/is_empty.hpp>
#include <boost/geometry/algorithms/detail/envelope/areal.hpp>
#include <boost/geometry/algorithms/detail/envelope/box.hpp>
#include <boost/geometry/algorithms/detail/envelope/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>
#include <boost/geometry/algorithms/detail/envelope/range.hpp>
#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
#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
@@ -0,0 +1,86 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP
#include <cstddef>
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
template <std::size_t Dimension, std::size_t DimensionCount>
struct initialize_loop
{
template <typename Box, typename CoordinateType>
static inline void apply(Box& box,
CoordinateType min_value,
CoordinateType max_value)
{
geometry::set<min_corner, Dimension>(box, min_value);
geometry::set<max_corner, Dimension>(box, max_value);
initialize_loop
<
Dimension + 1, DimensionCount
>::apply(box, min_value, max_value);
}
};
template <std::size_t DimensionCount>
struct initialize_loop<DimensionCount, DimensionCount>
{
template <typename Box, typename CoordinateType>
static inline void apply(Box&, CoordinateType, CoordinateType)
{
}
};
template
<
typename Box,
std::size_t Dimension = 0,
std::size_t DimensionCount = dimension<Box>::value
>
struct initialize
{
typedef typename coordinate_type<Box>::type coordinate_type;
static inline void apply(Box& box,
coordinate_type min_value
= boost::numeric::bounds<coordinate_type>::highest(),
coordinate_type max_value
= boost::numeric::bounds<coordinate_type>::lowest())
{
initialize_loop
<
Dimension, DimensionCount
>::apply(box, min_value, max_value);
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INITIALIZE_HPP
@@ -0,0 +1,234 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-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.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP
#include <boost/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/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
{
namespace resolve_strategy
{
template
<
typename Strategy,
bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
>
struct envelope
{
template <typename Geometry, typename Box>
static inline void apply(Geometry const& geometry,
Box& box,
Strategy const& strategy)
{
dispatch::envelope<Geometry>::apply(geometry, box, strategy);
}
};
template <typename Strategy>
struct envelope<Strategy, false>
{
template <typename Geometry, typename Box>
static inline void apply(Geometry const& geometry,
Box& box,
Strategy const& strategy)
{
using strategies::envelope::services::strategy_converter;
return dispatch::envelope
<
Geometry
>::apply(geometry, box, strategy_converter<Strategy>::get(strategy));
}
};
template <>
struct envelope<default_strategy, false>
{
template <typename Geometry, typename Box>
static inline void apply(Geometry const& geometry,
Box& box,
default_strategy)
{
typedef typename strategies::envelope::services::default_strategy
<
Geometry, Box
>::type strategy_type;
dispatch::envelope<Geometry>::apply(geometry, box, strategy_type());
}
};
} // namespace resolve_strategy
namespace resolve_dynamic
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct envelope
{
template <typename Box, typename Strategy>
static inline void apply(Geometry const& geometry,
Box& box,
Strategy const& strategy)
{
concepts::check<Geometry const>();
concepts::check<Box>();
resolve_strategy::envelope<Strategy>::apply(geometry, box, strategy);
}
};
template <typename Geometry>
struct envelope<Geometry, dynamic_geometry_tag>
{
template <typename Box, typename Strategy>
static inline void apply(Geometry const& geometry,
Box& box,
Strategy const& strategy)
{
traits::visit<Geometry>::apply([&](auto const& g)
{
envelope<util::remove_cref_t<decltype(g)>>::apply(g, box, strategy);
}, geometry);
}
};
} // namespace resolve_dynamic
/*!
\brief \brief_calc{envelope (with strategy)}
\ingroup envelope
\details \details_calc{envelope,\det_envelope}.
\tparam Geometry \tparam_geometry
\tparam Box \tparam_box
\tparam Strategy \tparam_strategy{Envelope}
\param geometry \param_geometry
\param mbr \param_box \param_set{envelope}
\param strategy \param_strategy{envelope}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/envelope.qbk]}
\qbk{
[heading Example]
[envelope] [envelope_output]
}
*/
template<typename Geometry, typename Box, typename Strategy>
inline void envelope(Geometry const& geometry, Box& mbr, Strategy const& strategy)
{
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy);
}
/*!
\brief \brief_calc{envelope}
\ingroup envelope
\details \details_calc{envelope,\det_envelope}.
\tparam Geometry \tparam_geometry
\tparam Box \tparam_box
\param geometry \param_geometry
\param mbr \param_box \param_set{envelope}
\qbk{[include reference/algorithms/envelope.qbk]}
\qbk{
[heading Example]
[envelope] [envelope_output]
}
*/
template<typename Geometry, typename Box>
inline void envelope(Geometry const& geometry, Box& mbr)
{
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy());
}
/*!
\brief \brief_calc{envelope}
\ingroup envelope
\details \details_calc{return_envelope,\det_envelope}. \details_return{envelope}
\tparam Box \tparam_box
\tparam Geometry \tparam_geometry
\tparam Strategy \tparam_strategy{Envelope}
\param geometry \param_geometry
\param strategy \param_strategy{envelope}
\return \return_calc{envelope}
\qbk{distinguish,with strategy}
\qbk{[include reference/algorithms/envelope.qbk]}
\qbk{
[heading Example]
[return_envelope] [return_envelope_output]
}
*/
template<typename Box, typename Geometry, typename Strategy>
inline Box return_envelope(Geometry const& geometry, Strategy const& strategy)
{
Box mbr;
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, strategy);
return mbr;
}
/*!
\brief \brief_calc{envelope}
\ingroup envelope
\details \details_calc{return_envelope,\det_envelope}. \details_return{envelope}
\tparam Box \tparam_box
\tparam Geometry \tparam_geometry
\param geometry \param_geometry
\return \return_calc{envelope}
\qbk{[include reference/algorithms/envelope.qbk]}
\qbk{
[heading Example]
[return_envelope] [return_envelope_output]
}
*/
template<typename Box, typename Geometry>
inline Box return_envelope(Geometry const& geometry)
{
Box mbr;
resolve_dynamic::envelope<Geometry>::apply(geometry, mbr, default_strategy());
return mbr;
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERFACE_HPP
@@ -0,0 +1,78 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_system.hpp>
#include <boost/geometry/util/math.hpp>
#include <boost/geometry/algorithms/detail/normalize.hpp>
namespace boost { namespace geometry
{
namespace detail { namespace envelope
{
struct intersects_antimeridian
{
template <typename Units, typename CoordinateType>
static inline bool apply(CoordinateType const& lon1,
CoordinateType const& lat1,
CoordinateType const& lon2,
CoordinateType const& lat2)
{
typedef math::detail::constants_on_spheroid
<
CoordinateType, Units
> constants;
return
math::equals(math::abs(lat1), constants::max_latitude())
||
math::equals(math::abs(lat2), constants::max_latitude())
||
math::larger(math::abs(lon1 - lon2), constants::half_period());
}
template <typename Segment>
static inline bool apply(Segment const& segment)
{
return apply(detail::indexed_point_view<Segment, 0>(segment),
detail::indexed_point_view<Segment, 1>(segment));
}
template <typename Point>
static inline bool apply(Point const& p1, Point const& p2)
{
Point p1_normalized = detail::return_normalized<Point>(p1);
Point p2_normalized = detail::return_normalized<Point>(p2);
return apply
<
typename coordinate_system<Point>::type::units
>(geometry::get<0>(p1_normalized),
geometry::get<1>(p1_normalized),
geometry::get<0>(p2_normalized),
geometry::get<1>(p2_normalized));
}
};
}} // namespace detail::envelope
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_INTERSECTS_ANTIMERIDIAN_HPP
+57
View File
@@ -0,0 +1,57 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-2020.
// Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/detail/envelope/range.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Linestring>
struct envelope<Linestring, linestring_tag>
: detail::envelope::envelope_range
{};
template <typename MultiLinestring>
struct envelope<MultiLinestring, multi_linestring_tag>
: detail::envelope::envelope_multi_range
<
detail::envelope::envelope_range
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_LINEAR_HPP
@@ -0,0 +1,47 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename MultiPoint>
struct envelope<MultiPoint, multi_point_tag>
{
template <typename Box, typename Strategy>
static inline void apply(MultiPoint const& multipoint, Box& mbr, Strategy const& strategy)
{
// strategy.envelope(multipoint, mbr).apply(multipoint, mbr);
using strategy_t = decltype(strategy.envelope(multipoint, mbr));
strategy_t::apply(multipoint, mbr);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_MULTIPOINT_HPP
+64
View File
@@ -0,0 +1,64 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015-2020.
// Modifications copyright (c) 2015-2020, Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/envelope.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace envelope
{
struct envelope_point
{
template <typename Point, typename Box, typename Strategy>
static inline void apply(Point const& point, Box& mbr, Strategy const& strategy)
{
// strategy.envelope(point, mbr).apply(point, mbr);
using strategy_t = decltype(strategy.envelope(point, mbr));
strategy_t::apply(point, mbr);
}
};
}} // namespace detail::envelope
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Point>
struct envelope<Point, point_tag>
: detail::envelope::envelope_point
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ENVELOPE_POINT_HPP

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