mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-10 07:34:03 +00:00
Merge pull request #987 from awulkiew/feature/gc7
Two GC-related utilities
This commit is contained in:
commit
dd32a9578b
@ -284,6 +284,10 @@ struct multi_to_multi: private Policy
|
|||||||
namespace 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
|
template
|
||||||
<
|
<
|
||||||
typename Geometry1, typename Geometry2,
|
typename Geometry1, typename Geometry2,
|
||||||
|
@ -32,6 +32,12 @@ namespace detail { namespace conversion
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Use assignment if possible.
|
||||||
|
// WARNING: This utility is called in various places for a subset of dimensions.
|
||||||
|
// In such cases only some of the coordinates should be copied. Alternatively
|
||||||
|
// there should be a different utility for that called differently than
|
||||||
|
// convert_xxx, e.g. set_coordinates.
|
||||||
|
|
||||||
template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount>
|
template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount>
|
||||||
struct point_to_point
|
struct point_to_point
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
||||||
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
||||||
|
|
||||||
// This file was modified by Oracle on 2017-2020.
|
// This file was modified by Oracle on 2017-2022.
|
||||||
// Modifications copyright (c) 2017-2020 Oracle and/or its affiliates.
|
// Modifications copyright (c) 2017-2022 Oracle and/or its affiliates.
|
||||||
// Contributed and/or modified by Adam Wulkiewicz, 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
|
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
||||||
@ -25,17 +25,15 @@
|
|||||||
#include <boost/range/end.hpp>
|
#include <boost/range/end.hpp>
|
||||||
#include <boost/static_assert.hpp>
|
#include <boost/static_assert.hpp>
|
||||||
|
|
||||||
#include <boost/geometry/core/tags.hpp>
|
|
||||||
#include <boost/geometry/core/point_type.hpp>
|
|
||||||
#include <boost/geometry/core/ring_type.hpp>
|
|
||||||
|
|
||||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
|
||||||
|
|
||||||
#include <boost/geometry/algorithms/assign.hpp>
|
#include <boost/geometry/algorithms/assign.hpp>
|
||||||
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
|
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
|
||||||
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
|
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
|
||||||
|
#include <boost/geometry/core/tags.hpp>
|
||||||
|
#include <boost/geometry/core/point_type.hpp>
|
||||||
|
#include <boost/geometry/core/ring_type.hpp>
|
||||||
|
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||||
#include <boost/geometry/util/condition.hpp>
|
#include <boost/geometry/util/condition.hpp>
|
||||||
|
#include <boost/geometry/views/detail/indexed_point_view.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace boost { namespace geometry
|
namespace boost { namespace geometry
|
||||||
@ -49,10 +47,10 @@ namespace detail { namespace point_on_border
|
|||||||
|
|
||||||
struct get_point
|
struct get_point
|
||||||
{
|
{
|
||||||
template <typename Point>
|
template <typename Destination, typename Source>
|
||||||
static inline bool apply(Point& destination, Point const& source)
|
static inline bool apply(Destination& destination, Source const& source)
|
||||||
{
|
{
|
||||||
destination = source;
|
detail::conversion::convert_point_to_point(source, destination);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -69,7 +67,7 @@ struct point_on_range
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry::detail::conversion::convert_point_to_point(*begin, point);
|
detail::conversion::convert_point_to_point(*begin, point);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,12 +90,13 @@ struct point_on_polygon
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct point_on_box
|
struct point_on_segment_or_box
|
||||||
{
|
{
|
||||||
template<typename Point, typename Box>
|
template<typename Point, typename SegmentOrBox>
|
||||||
static inline bool apply(Point& point, Box const& box)
|
static inline bool apply(Point& point, SegmentOrBox const& segment_or_box)
|
||||||
{
|
{
|
||||||
detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point);
|
detail::indexed_point_view<SegmentOrBox const, 0> view(segment_or_box);
|
||||||
|
detail::conversion::convert_point_to_point(view, point);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -146,6 +145,11 @@ struct point_on_border<point_tag>
|
|||||||
: detail::point_on_border::get_point
|
: detail::point_on_border::get_point
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct point_on_border<segment_tag>
|
||||||
|
: detail::point_on_border::point_on_segment_or_box
|
||||||
|
{};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct point_on_border<linestring_tag>
|
struct point_on_border<linestring_tag>
|
||||||
: detail::point_on_border::point_on_range
|
: detail::point_on_border::point_on_range
|
||||||
@ -163,10 +167,15 @@ struct point_on_border<polygon_tag>
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct point_on_border<box_tag>
|
struct point_on_border<box_tag>
|
||||||
: detail::point_on_border::point_on_box
|
: detail::point_on_border::point_on_segment_or_box
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct point_on_border<multi_point_tag>
|
||||||
|
: detail::point_on_border::point_on_range
|
||||||
|
{};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct point_on_border<multi_polygon_tag>
|
struct point_on_border<multi_polygon_tag>
|
||||||
: detail::point_on_border::point_on_multi
|
: detail::point_on_border::point_on_multi
|
||||||
@ -189,6 +198,9 @@ struct point_on_border<multi_linestring_tag>
|
|||||||
#endif // DOXYGEN_NO_DISPATCH
|
#endif // DOXYGEN_NO_DISPATCH
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: We should probably rename this utility because it can return point
|
||||||
|
// which is in the interior of a geometry (for PointLike and LinearRings).
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Take point on a border
|
\brief Take point on a border
|
||||||
\ingroup overlay
|
\ingroup overlay
|
||||||
|
403
include/boost/geometry/algorithms/merge_elements.hpp
Normal file
403
include/boost/geometry/algorithms/merge_elements.hpp
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
// Boost.Geometry
|
||||||
|
|
||||||
|
// Copyright (c) 2022, 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_MERGE_ELEMENTS_HPP
|
||||||
|
#define BOOST_GEOMETRY_ALGORITHMS_MERGE_ELEMENTS_HPP
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/geometry/algorithms/detail/point_on_border.hpp>
|
||||||
|
#include <boost/geometry/algorithms/detail/visit.hpp>
|
||||||
|
#include <boost/geometry/algorithms/difference.hpp>
|
||||||
|
#include <boost/geometry/algorithms/union.hpp>
|
||||||
|
#include <boost/geometry/core/coordinate_system.hpp>
|
||||||
|
#include <boost/geometry/core/coordinate_type.hpp>
|
||||||
|
#include <boost/geometry/core/point_type.hpp>
|
||||||
|
#include <boost/geometry/core/tag.hpp>
|
||||||
|
#include <boost/geometry/core/tags.hpp>
|
||||||
|
#include <boost/geometry/core/visit.hpp>
|
||||||
|
#include <boost/geometry/geometries/point.hpp>
|
||||||
|
#include <boost/geometry/policies/compare.hpp>
|
||||||
|
#include <boost/geometry/util/range.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/strategies/spherical/compare.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace boost { namespace geometry
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_NO_DETAIL
|
||||||
|
namespace detail { namespace merge_elements
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using is_pla = util::bool_constant<util::is_pointlike<T>::value || util::is_linear<T>::value || util::is_areal<T>::value>;
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
struct are_areal : util::bool_constant<util::is_areal<T>::value && are_areal<Ts...>::value> {};
|
||||||
|
template <typename T>
|
||||||
|
struct are_areal<T> : util::is_areal<T> {};
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
struct are_linear : util::bool_constant<util::is_linear<T>::value && are_linear<Ts...>::value> {};
|
||||||
|
template <typename T>
|
||||||
|
struct are_linear<T> : util::is_linear<T> {};
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
struct are_pointlike : util::bool_constant<util::is_pointlike<T>::value && are_pointlike<Ts...>::value> {};
|
||||||
|
template <typename T>
|
||||||
|
struct are_pointlike<T> : util::is_pointlike<T> {};
|
||||||
|
template <typename ...Ts>
|
||||||
|
using are_same_kind = util::bool_constant<are_areal<Ts...>::value || are_linear<Ts...>::value || are_pointlike<Ts...>::value>;
|
||||||
|
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry, typename It, typename PointLike, typename Linear, typename Areal,
|
||||||
|
std::enable_if_t<util::is_areal<Geometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void distribute_element(Geometry const& geometry, It it, PointLike& , Linear&, Areal& areal)
|
||||||
|
{
|
||||||
|
typename geometry::point_type<Geometry>::type point;
|
||||||
|
if (geometry::point_on_border(point, geometry))
|
||||||
|
{
|
||||||
|
using point_t = typename Areal::value_type::first_type;
|
||||||
|
areal.emplace_back(point_t(geometry::get<0>(point), geometry::get<1>(point)), it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry, typename It, typename PointLike, typename Linear, typename Areal,
|
||||||
|
std::enable_if_t<util::is_linear<Geometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void distribute_element(Geometry const& geometry, It it, PointLike& , Linear& linear, Areal& )
|
||||||
|
{
|
||||||
|
typename geometry::point_type<Geometry>::type point;
|
||||||
|
if (geometry::point_on_border(point, geometry))
|
||||||
|
{
|
||||||
|
using point_t = typename Linear::value_type::first_type;
|
||||||
|
linear.emplace_back(point_t(geometry::get<0>(point), geometry::get<1>(point)), it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry, typename It, typename PointLike, typename Linear, typename Areal,
|
||||||
|
std::enable_if_t<util::is_pointlike<Geometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void distribute_element(Geometry const& geometry, It it, PointLike& pointlike, Linear& , Areal& )
|
||||||
|
{
|
||||||
|
typename geometry::point_type<Geometry>::type point;
|
||||||
|
if (geometry::point_on_border(point, geometry))
|
||||||
|
{
|
||||||
|
using point_t = typename Linear::value_type::first_type;
|
||||||
|
pointlike.emplace_back(point_t(geometry::get<0>(point), geometry::get<1>(point)), it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry, typename It, typename PointLike, typename Linear, typename Areal,
|
||||||
|
std::enable_if_t<! is_pla<Geometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void distribute_element(Geometry const& , It , PointLike& , Linear&, Areal&)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry, typename MultiGeometry,
|
||||||
|
std::enable_if_t<are_same_kind<Geometry, MultiGeometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void convert(Geometry const& geometry, MultiGeometry& result)
|
||||||
|
{
|
||||||
|
geometry::convert(geometry, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry, typename MultiGeometry,
|
||||||
|
std::enable_if_t<! are_same_kind<Geometry, MultiGeometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void convert(Geometry const& , MultiGeometry& )
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry1, typename Geometry2, typename MultiGeometry, typename Strategy,
|
||||||
|
std::enable_if_t<are_same_kind<Geometry1, Geometry2, MultiGeometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void union_(Geometry1 const& geometry1, Geometry2 const& geometry2, MultiGeometry& result, Strategy const& strategy)
|
||||||
|
{
|
||||||
|
geometry::union_(geometry1, geometry2, result, strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename Geometry1, typename Geometry2, typename MultiGeometry, typename Strategy,
|
||||||
|
std::enable_if_t<! are_same_kind<Geometry1, Geometry2, MultiGeometry>::value, int> = 0
|
||||||
|
>
|
||||||
|
inline void union_(Geometry1 const& , Geometry2 const& , MultiGeometry& , Strategy const&)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename It>
|
||||||
|
struct merge_data
|
||||||
|
{
|
||||||
|
merge_data(It first_, It last_)
|
||||||
|
: first(first_), last(last_)
|
||||||
|
{}
|
||||||
|
It first, last;
|
||||||
|
bool merge_results = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename GeometryCollection, typename RandomIt, typename MultiGeometry, typename Strategy>
|
||||||
|
inline void merge(RandomIt const first, RandomIt const last, MultiGeometry& out, Strategy const& strategy)
|
||||||
|
{
|
||||||
|
auto const size = last - first;
|
||||||
|
if (size <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const less = [](auto const& l, auto const& r)
|
||||||
|
{
|
||||||
|
return geometry::less<void, -1, typename Strategy::cs_tag>()(l.first, r.first);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<merge_data<RandomIt>> stack_in;
|
||||||
|
std::vector<MultiGeometry> stack_out;
|
||||||
|
stack_in.reserve(size / 2 + 1);
|
||||||
|
stack_out.reserve(size / 2 + 1);
|
||||||
|
|
||||||
|
stack_in.emplace_back(first, last);
|
||||||
|
|
||||||
|
while (! stack_in.empty())
|
||||||
|
{
|
||||||
|
auto & b = stack_in.back();
|
||||||
|
if (! b.merge_results)
|
||||||
|
{
|
||||||
|
auto const s = b.last - b.first;
|
||||||
|
if (s > 2)
|
||||||
|
{
|
||||||
|
RandomIt const mid = b.first + s / 2;
|
||||||
|
std::nth_element(b.first, mid, b.last, less);
|
||||||
|
RandomIt const fir = b.first;
|
||||||
|
RandomIt const las = b.last;
|
||||||
|
b.merge_results = true;
|
||||||
|
stack_in.emplace_back(fir, mid);
|
||||||
|
stack_in.emplace_back(mid, las);
|
||||||
|
}
|
||||||
|
else if (s == 2)
|
||||||
|
{
|
||||||
|
MultiGeometry result;
|
||||||
|
traits::iter_visit<GeometryCollection>::apply([&](auto const& g1)
|
||||||
|
{
|
||||||
|
traits::iter_visit<GeometryCollection>::apply([&](auto const& g2)
|
||||||
|
{
|
||||||
|
merge_elements::union_(g1, g2, result, strategy);
|
||||||
|
}, (b.first + 1)->second);
|
||||||
|
}, b.first->second);
|
||||||
|
stack_out.push_back(std::move(result));
|
||||||
|
stack_in.pop_back();
|
||||||
|
}
|
||||||
|
else if (s == 1)
|
||||||
|
{
|
||||||
|
MultiGeometry result;
|
||||||
|
traits::iter_visit<GeometryCollection>::apply([&](auto const& g)
|
||||||
|
{
|
||||||
|
merge_elements::convert(g, result);
|
||||||
|
}, b.first->second);
|
||||||
|
stack_out.push_back(std::move(result));
|
||||||
|
stack_in.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (b.merge_results)
|
||||||
|
{
|
||||||
|
MultiGeometry m2 = std::move(stack_out.back());
|
||||||
|
stack_out.pop_back();
|
||||||
|
MultiGeometry m1 = std::move(stack_out.back());
|
||||||
|
stack_out.pop_back();
|
||||||
|
MultiGeometry result;
|
||||||
|
geometry::union_(m1, m2, result, strategy);
|
||||||
|
stack_out.push_back(std::move(result));
|
||||||
|
stack_in.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out = std::move(stack_out.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct merge_gc
|
||||||
|
{
|
||||||
|
template <typename GeometryCollection, typename Strategy>
|
||||||
|
static void apply(GeometryCollection const& geometry_collection,
|
||||||
|
GeometryCollection & out,
|
||||||
|
Strategy const& strategy)
|
||||||
|
{
|
||||||
|
using original_point_t = typename geometry::point_type<GeometryCollection>::type;
|
||||||
|
using iterator_t = typename boost::range_iterator<GeometryCollection const>::type;
|
||||||
|
using coordinate_t = typename geometry::coordinate_type<original_point_t>::type;
|
||||||
|
using cs_t = typename geometry::coordinate_system<original_point_t>::type;
|
||||||
|
using point_t = model::point<coordinate_t, 2, cs_t>;
|
||||||
|
|
||||||
|
using multi_point_t = typename util::sequence_find_if
|
||||||
|
<
|
||||||
|
typename traits::geometry_types<std::remove_const_t<GeometryCollection>>::type,
|
||||||
|
util::is_multi_point
|
||||||
|
>::type;
|
||||||
|
using multi_linestring_t = typename util::sequence_find_if
|
||||||
|
<
|
||||||
|
typename traits::geometry_types<std::remove_const_t<GeometryCollection>>::type,
|
||||||
|
util::is_multi_linestring
|
||||||
|
>::type;
|
||||||
|
using multi_polygon_t = typename util::sequence_find_if
|
||||||
|
<
|
||||||
|
typename traits::geometry_types<std::remove_const_t<GeometryCollection>>::type,
|
||||||
|
util::is_multi_polygon
|
||||||
|
>::type;
|
||||||
|
|
||||||
|
// NOTE: Right now GC containing all of the above is required but technically
|
||||||
|
// we could allow only some combinations and the algorithm below could
|
||||||
|
// normalize GC accordingly.
|
||||||
|
|
||||||
|
multi_point_t multi_point, multi_point2;
|
||||||
|
multi_linestring_t multi_linestring, multi_linestring2;
|
||||||
|
multi_polygon_t multi_polygon;
|
||||||
|
|
||||||
|
std::vector<std::pair<point_t, iterator_t>> pointlike;
|
||||||
|
std::vector<std::pair<point_t, iterator_t>> linear;
|
||||||
|
std::vector<std::pair<point_t, iterator_t>> areal;
|
||||||
|
|
||||||
|
detail::visit_breadth_first_impl<true>::apply([&](auto const& g, auto it)
|
||||||
|
{
|
||||||
|
merge_elements::distribute_element(g, it, pointlike, linear, areal);
|
||||||
|
return true;
|
||||||
|
}, geometry_collection);
|
||||||
|
|
||||||
|
// TODO: make this optional?
|
||||||
|
// TODO: merge linear at the end? (difference can break linear rings, their parts would be joined)
|
||||||
|
merge<GeometryCollection>(pointlike.begin(), pointlike.end(), multi_point, strategy);
|
||||||
|
merge<GeometryCollection>(linear.begin(), linear.end(), multi_linestring, strategy);
|
||||||
|
|
||||||
|
merge<GeometryCollection>(areal.begin(), areal.end(), multi_polygon, strategy);
|
||||||
|
|
||||||
|
// L \ A
|
||||||
|
geometry::difference(multi_linestring, multi_polygon, multi_linestring2, strategy);
|
||||||
|
|
||||||
|
// (P \ A) \ L
|
||||||
|
geometry::difference(multi_point, multi_polygon, multi_point2, strategy);
|
||||||
|
range::clear(multi_point);
|
||||||
|
geometry::difference(multi_point2, multi_linestring2, multi_point, strategy);
|
||||||
|
|
||||||
|
if (! geometry::is_empty(multi_point))
|
||||||
|
{
|
||||||
|
range::emplace_back(out, std::move(multi_point));
|
||||||
|
}
|
||||||
|
if (! geometry::is_empty(multi_linestring2))
|
||||||
|
{
|
||||||
|
range::emplace_back(out, std::move(multi_linestring2));
|
||||||
|
}
|
||||||
|
if (! geometry::is_empty(multi_polygon))
|
||||||
|
{
|
||||||
|
range::emplace_back(out, std::move(multi_polygon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace detail::merge_elements
|
||||||
|
#endif // DOXYGEN_NO_DETAIL
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_NO_DISPATCH
|
||||||
|
namespace dispatch
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
|
||||||
|
struct merge_elements
|
||||||
|
: not_implemented<Geometry, Tag>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename GeometryCollection>
|
||||||
|
struct merge_elements<GeometryCollection, geometry_collection_tag>
|
||||||
|
: geometry::detail::merge_elements::merge_gc
|
||||||
|
{};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace dispatch
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace resolve_strategy
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Strategy>
|
||||||
|
struct merge_elements
|
||||||
|
{
|
||||||
|
template <typename Geometry>
|
||||||
|
static void apply(Geometry const& geometry, Geometry & out, Strategy const& strategy)
|
||||||
|
{
|
||||||
|
dispatch::merge_elements
|
||||||
|
<
|
||||||
|
Geometry
|
||||||
|
>::apply(geometry, out, strategy);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct merge_elements<default_strategy>
|
||||||
|
{
|
||||||
|
template <typename Geometry>
|
||||||
|
static void apply(Geometry const& geometry, Geometry & out, default_strategy)
|
||||||
|
{
|
||||||
|
using strategy_type = typename strategies::relate::services::default_strategy
|
||||||
|
<
|
||||||
|
Geometry, Geometry
|
||||||
|
>::type;
|
||||||
|
|
||||||
|
dispatch::merge_elements
|
||||||
|
<
|
||||||
|
Geometry
|
||||||
|
>::apply(geometry, out, strategy_type());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace resolve_strategy
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Geometry, typename Strategy>
|
||||||
|
inline void merge_elements(Geometry const& geometry, Geometry & out, Strategy const& strategy)
|
||||||
|
{
|
||||||
|
resolve_strategy::merge_elements
|
||||||
|
<
|
||||||
|
Strategy
|
||||||
|
>::apply(geometry, out, strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Geometry>
|
||||||
|
inline void merge_elements(Geometry const& geometry, Geometry & out)
|
||||||
|
{
|
||||||
|
resolve_strategy::merge_elements
|
||||||
|
<
|
||||||
|
default_strategy
|
||||||
|
>::apply(geometry, out, default_strategy());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace boost::geometry
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_GEOMETRY_ALGORITHMS_MERGE_ELEMENTS_HPP
|
204
include/boost/geometry/views/detail/random_access_view.hpp
Normal file
204
include/boost/geometry/views/detail/random_access_view.hpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
// Boost.Geometry
|
||||||
|
|
||||||
|
// Copyright (c) 2022, 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_VIEWS_DETAIL_RANDOM_ACCESS_VIEW_HPP
|
||||||
|
#define BOOST_GEOMETRY_VIEWS_DETAIL_RANDOM_ACCESS_VIEW_HPP
|
||||||
|
|
||||||
|
#include <boost/range/begin.hpp>
|
||||||
|
#include <boost/range/end.hpp>
|
||||||
|
#include <boost/range/iterator.hpp>
|
||||||
|
#include <boost/range/size.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/algorithms/detail/visit.hpp>
|
||||||
|
#include <boost/geometry/core/geometry_types.hpp>
|
||||||
|
#include <boost/geometry/core/tag.hpp>
|
||||||
|
#include <boost/geometry/core/tags.hpp>
|
||||||
|
#include <boost/geometry/util/sequence.hpp>
|
||||||
|
#include <boost/geometry/util/type_traits.hpp>
|
||||||
|
|
||||||
|
namespace boost { namespace geometry
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_NO_DETAIL
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
struct is_random_access_range
|
||||||
|
: std::is_convertible
|
||||||
|
<
|
||||||
|
typename boost::iterator_traversal
|
||||||
|
<
|
||||||
|
typename boost::range_iterator<Range>::type
|
||||||
|
>::type,
|
||||||
|
boost::random_access_traversal_tag
|
||||||
|
>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename Geometry>
|
||||||
|
struct is_geometry_collection_recursive
|
||||||
|
: util::bool_constant
|
||||||
|
<
|
||||||
|
util::is_geometry_collection
|
||||||
|
<
|
||||||
|
typename util::sequence_find_if
|
||||||
|
<
|
||||||
|
typename traits::geometry_types<std::remove_const_t<Geometry>>::type,
|
||||||
|
util::is_geometry_collection
|
||||||
|
>::type
|
||||||
|
>::value
|
||||||
|
>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template
|
||||||
|
<
|
||||||
|
typename GeometryCollection,
|
||||||
|
bool IsRandomAccess = is_random_access_range<GeometryCollection>::value,
|
||||||
|
bool IsRecursive = is_geometry_collection_recursive<GeometryCollection>::value
|
||||||
|
>
|
||||||
|
class random_access_view
|
||||||
|
: public std::vector<typename boost::range_iterator<GeometryCollection>::type>
|
||||||
|
{
|
||||||
|
// NOTE: An alternative would be to implement iterator holding base iterators
|
||||||
|
// to geometry collections of lower levels to process after the current level
|
||||||
|
// of bfs traversal is finished.
|
||||||
|
|
||||||
|
using base_t = std::vector<typename boost::range_iterator<GeometryCollection>::type>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
random_access_view(GeometryCollection & geometry)
|
||||||
|
{
|
||||||
|
this->reserve(boost::size(geometry));
|
||||||
|
detail::visit_breadth_first_impl<true>::apply([&](auto&&, auto iter)
|
||||||
|
{
|
||||||
|
this->push_back(iter);
|
||||||
|
return true;
|
||||||
|
}, geometry);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename GeometryCollection>
|
||||||
|
class random_access_view<GeometryCollection, true, false>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using iterator = typename boost::range_iterator<GeometryCollection>::type;
|
||||||
|
using const_iterator = typename boost::range_const_iterator<GeometryCollection>::type;
|
||||||
|
|
||||||
|
random_access_view(GeometryCollection & geometry)
|
||||||
|
: m_begin(boost::begin(geometry))
|
||||||
|
, m_end(boost::end(geometry))
|
||||||
|
{}
|
||||||
|
|
||||||
|
iterator begin() { return m_begin; }
|
||||||
|
iterator end() { return m_end; }
|
||||||
|
const_iterator begin() const { return m_begin; }
|
||||||
|
const_iterator end() const { return m_end; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
iterator m_begin, m_end;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename GeometryCollection>
|
||||||
|
struct random_access_view_iter_visit
|
||||||
|
{
|
||||||
|
template <typename Function, typename Iterator>
|
||||||
|
static void apply(Function && function, Iterator iterator)
|
||||||
|
{
|
||||||
|
geometry::traits::iter_visit
|
||||||
|
<
|
||||||
|
std::remove_const_t<GeometryCollection>
|
||||||
|
>::apply(std::forward<Function>(function), *iterator);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename ...Ts>
|
||||||
|
struct remove_geometry_collections_pack
|
||||||
|
{
|
||||||
|
using type = util::type_sequence<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
struct remove_geometry_collections_pack<T, Ts...>
|
||||||
|
{
|
||||||
|
using next_sequence = typename remove_geometry_collections_pack<Ts...>::type;
|
||||||
|
using type = std::conditional_t
|
||||||
|
<
|
||||||
|
util::is_geometry_collection<T>::value,
|
||||||
|
next_sequence,
|
||||||
|
typename util::sequence_merge<util::type_sequence<T>, next_sequence>::type
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Types>
|
||||||
|
struct remove_geometry_collections;
|
||||||
|
|
||||||
|
template <typename ...Ts>
|
||||||
|
struct remove_geometry_collections<util::type_sequence<Ts...>>
|
||||||
|
: remove_geometry_collections_pack<Ts...>
|
||||||
|
{};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
#endif // DOXYGEN_NO_DETAIL
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DOXYGEN_NO_TRAITS_SPECIALIZATIONS
|
||||||
|
namespace traits
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename GeometryCollection, bool IsRandomAccess, bool IsRecursive>
|
||||||
|
struct tag<geometry::detail::random_access_view<GeometryCollection, IsRandomAccess, IsRecursive>>
|
||||||
|
{
|
||||||
|
using type = geometry_collection_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename GeometryCollection>
|
||||||
|
struct iter_visit<geometry::detail::random_access_view<GeometryCollection, false, false>>
|
||||||
|
: geometry::detail::random_access_view_iter_visit<GeometryCollection>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename GeometryCollection>
|
||||||
|
struct iter_visit<geometry::detail::random_access_view<GeometryCollection, true, true>>
|
||||||
|
: geometry::detail::random_access_view_iter_visit<GeometryCollection>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename GeometryCollection>
|
||||||
|
struct iter_visit<geometry::detail::random_access_view<GeometryCollection, false, true>>
|
||||||
|
: geometry::detail::random_access_view_iter_visit<GeometryCollection>
|
||||||
|
{};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename GeometryCollection, bool IsRandomAccess>
|
||||||
|
struct geometry_types<geometry::detail::random_access_view<GeometryCollection, IsRandomAccess, false>>
|
||||||
|
: geometry_types<GeometryCollection>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename GeometryCollection, bool IsRandomAccess>
|
||||||
|
struct geometry_types<geometry::detail::random_access_view<GeometryCollection, IsRandomAccess, true>>
|
||||||
|
: geometry::detail::remove_geometry_collections
|
||||||
|
<
|
||||||
|
typename traits::geometry_types
|
||||||
|
<
|
||||||
|
std::remove_const_t<GeometryCollection>
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
{};
|
||||||
|
|
||||||
|
} // namespace traits
|
||||||
|
#endif // DOXYGEN_NO_TRAITS_SPECIALIZATIONS
|
||||||
|
|
||||||
|
|
||||||
|
}} // namespace boost::geometry
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOST_GEOMETRY_VIEWS_DETAIL_RANDOM_ACCESS_VIEW_HPP
|
@ -5,8 +5,8 @@
|
|||||||
# Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
|
# Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
|
||||||
# Copyright (c) 2018 Adam Wulkiewicz, Lodz, Poland.
|
# Copyright (c) 2018 Adam Wulkiewicz, Lodz, Poland.
|
||||||
#
|
#
|
||||||
# This file was modified by Oracle on 2014-2021.
|
# This file was modified by Oracle on 2014-2022.
|
||||||
# Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
|
# Modifications copyright (c) 2014-2022, Oracle and/or its affiliates.
|
||||||
#
|
#
|
||||||
# Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
|
# Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
|
||||||
# Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
|
# Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
|
||||||
@ -45,6 +45,7 @@ test-suite boost-geometry-algorithms
|
|||||||
[ run line_interpolate.cpp : : : : algorithms_line_interpolate ]
|
[ run line_interpolate.cpp : : : : algorithms_line_interpolate ]
|
||||||
[ run make.cpp : : : : algorithms_make ]
|
[ run make.cpp : : : : algorithms_make ]
|
||||||
[ run maximum_gap.cpp : : : : algorithms_maximum_gap ]
|
[ run maximum_gap.cpp : : : : algorithms_maximum_gap ]
|
||||||
|
[ run merge_elements.cpp : : : : algorithms_merge_elements ]
|
||||||
[ run num_geometries.cpp : : : : algorithms_num_geometries ]
|
[ run num_geometries.cpp : : : : algorithms_num_geometries ]
|
||||||
[ run num_geometries_multi.cpp : : : : algorithms_num_geometries_multi ]
|
[ run num_geometries_multi.cpp : : : : algorithms_num_geometries_multi ]
|
||||||
[ run num_interior_rings.cpp : : : : algorithms_num_interior_rings ]
|
[ run num_interior_rings.cpp : : : : algorithms_num_interior_rings ]
|
||||||
|
77
test/algorithms/merge_elements.cpp
Normal file
77
test/algorithms/merge_elements.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Boost.Geometry
|
||||||
|
// Unit Test
|
||||||
|
|
||||||
|
// Copyright (c) 2022, 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
|
||||||
|
|
||||||
|
|
||||||
|
#include <geometry_test_common.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/algorithms/area.hpp>
|
||||||
|
#include <boost/geometry/algorithms/length.hpp>
|
||||||
|
#include <boost/geometry/algorithms/merge_elements.hpp>
|
||||||
|
#include <boost/geometry/algorithms/perimeter.hpp>
|
||||||
|
#include <boost/geometry/geometries/adapted/boost_variant2.hpp>
|
||||||
|
#include <boost/geometry/geometries/geometries.hpp>
|
||||||
|
#include <boost/geometry/io/wkt/wkt.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
void test_all(std::size_t points_count, std::size_t linestrings_count, std::size_t polygons_count,
|
||||||
|
double length, double perimeter, double area)
|
||||||
|
{
|
||||||
|
using pt_t = P;
|
||||||
|
using mpt_t = bg::model::multi_point<pt_t>;
|
||||||
|
using seg_t = bg::model::segment<pt_t>;
|
||||||
|
using ls_t = bg::model::linestring<pt_t>;
|
||||||
|
using mls_t = bg::model::multi_linestring<ls_t>;
|
||||||
|
using box_t = bg::model::box<pt_t>;
|
||||||
|
using ring_t = bg::model::ring<pt_t>;
|
||||||
|
using poly_t = bg::model::polygon<pt_t>;
|
||||||
|
using mpoly_t = bg::model::multi_polygon<poly_t>;
|
||||||
|
using var_t = boost::variant<pt_t, mpt_t/*, seg_t*/, ls_t, mls_t, /*box_t,*/ ring_t, poly_t, mpoly_t>;
|
||||||
|
//using var_t = boost::variant2::variant<pt_t, mpt_t/*, seg_t*/, ls_t, mls_t, /*box_t,*/ ring_t, poly_t, mpoly_t>;
|
||||||
|
using gc_t = bg::model::geometry_collection<var_t>;
|
||||||
|
|
||||||
|
gc_t gc{
|
||||||
|
poly_t{{{0, 0},{0, 10},{10, 10},{10, 0},{0, 0}}, {{1, 1},{5, 1},{5, 5},{1, 5},{1, 1}}},
|
||||||
|
mpoly_t{{{{4, 4},{4, 6},{6, 6},{6, 4},{4, 4}}}, {{{10, 10},{10, 12},{12, 12},{12, 10},{10, 10}}}},
|
||||||
|
ring_t{{11, 11},{11, 14},{14, 14},{14, 11},{11, 11}},
|
||||||
|
//box_t{{13, 13}, {16, 16}},
|
||||||
|
mls_t{{{0, 0},{20, 20}}, {{3, 3},{3, 6},{6, 6},{6, 3},{3, 3}}},
|
||||||
|
ls_t{{3, 3},{3, 20}},
|
||||||
|
mpt_t{{2, 2},{2, 2},{5, 5},{9, 9},{11, 11},{0, 20},{1, 20}},
|
||||||
|
pt_t{0, 20}
|
||||||
|
};
|
||||||
|
|
||||||
|
gc_t result;
|
||||||
|
bg::merge_elements(gc, result);
|
||||||
|
|
||||||
|
BOOST_CHECK(boost::get<mpt_t>(result[0]).size() == points_count);
|
||||||
|
BOOST_CHECK(boost::get<mls_t>(result[1]).size() == linestrings_count);
|
||||||
|
BOOST_CHECK(boost::get<mpoly_t>(result[2]).size() == polygons_count);
|
||||||
|
auto l = bg::length(result);
|
||||||
|
auto a = bg::area(result);
|
||||||
|
auto p = bg::perimeter(result);
|
||||||
|
decltype(l) l_expected = length;
|
||||||
|
decltype(p) p_expected = perimeter;
|
||||||
|
decltype(a) a_expected = area;
|
||||||
|
BOOST_CHECK_CLOSE(l, l_expected, 0.000001);
|
||||||
|
BOOST_CHECK_CLOSE(p, p_expected, 0.000001);
|
||||||
|
BOOST_CHECK_CLOSE(a, a_expected, 0.000001);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main(int, char* [])
|
||||||
|
{
|
||||||
|
test_all<bg::model::point<double, 2, bg::cs::cartesian>>(2, 5, 2, std::sqrt(2.0) * (3 + 6) + 4 + 10, 72, 97);
|
||||||
|
// TODO: right now the elements of multi geometries are not merged,
|
||||||
|
// only different geometries stored in a GC. Hence duplicated point in the result.
|
||||||
|
test_all<bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree>>>(4, 6, 2, 0.48141804683843953, 1.2506937915396685, 0.029392562222852522);
|
||||||
|
test_all<bg::model::point<double, 2, bg::cs::geographic<bg::degree>>>(4, 6, 2, 3058383.6297531724, 7951118.1434133006, 1187967114570.5911);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -5,15 +5,20 @@
|
|||||||
# Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
|
# Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
|
||||||
# Copyright (c) 2015 Adam Wulkiewicz, Lodz, Poland.
|
# Copyright (c) 2015 Adam Wulkiewicz, Lodz, Poland.
|
||||||
#
|
#
|
||||||
|
# This file was modified by Oracle on 2022.
|
||||||
|
# Modifications 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,
|
# Use, modification and distribution is subject to the Boost Software License,
|
||||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
test-suite boost-geometry-views
|
test-suite boost-geometry-views
|
||||||
:
|
:
|
||||||
[ run segment_view.cpp : : : : views_segment_view ]
|
|
||||||
[ run box_view.cpp : : : : views_box_view ]
|
[ run box_view.cpp : : : : views_box_view ]
|
||||||
[ run reversible_view.cpp : : : : views_reversible_view ]
|
|
||||||
[ run closeable_view.cpp : : : : views_closeable_view ]
|
[ run closeable_view.cpp : : : : views_closeable_view ]
|
||||||
|
[ run random_access_view.cpp : : : : views_random_access_view ]
|
||||||
[ run reversible_closeable.cpp : : : : views_reversible_closeable ]
|
[ run reversible_closeable.cpp : : : : views_reversible_closeable ]
|
||||||
|
[ run reversible_view.cpp : : : : views_reversible_view ]
|
||||||
|
[ run segment_view.cpp : : : : views_segment_view ]
|
||||||
;
|
;
|
||||||
|
123
test/views/random_access_view.cpp
Normal file
123
test/views/random_access_view.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Boost.Geometry
|
||||||
|
// Unit Test
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
|
||||||
|
#include <geometry_test_common.hpp>
|
||||||
|
|
||||||
|
#include <boost/variant.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/views/detail/random_access_view.hpp>
|
||||||
|
#include <boost/geometry/geometries/geometries.hpp>
|
||||||
|
|
||||||
|
using point_t = bg::model::point<double, 2, bg::cs::cartesian>;
|
||||||
|
using linestring_t = bg::model::linestring<point_t>;
|
||||||
|
using polygon_t = bg::model::polygon<point_t>;
|
||||||
|
using variant_t = boost::variant<point_t, linestring_t, polygon_t>;
|
||||||
|
using gc_t = bg::model::geometry_collection<variant_t>;
|
||||||
|
using nra_gc_t = bg::model::geometry_collection<variant_t, std::list>;
|
||||||
|
|
||||||
|
struct rec_gc_t;
|
||||||
|
using rec_var_t = boost::variant<point_t, linestring_t, polygon_t, rec_gc_t>;
|
||||||
|
struct rec_gc_t : std::vector<rec_var_t>
|
||||||
|
{
|
||||||
|
rec_gc_t() = default;
|
||||||
|
rec_gc_t(std::initializer_list<rec_var_t> l) : std::vector<rec_var_t>(l) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rec_nra_gc_t;
|
||||||
|
using rec_nra_var_t = boost::variant<point_t, linestring_t, polygon_t, rec_nra_gc_t>;
|
||||||
|
struct rec_nra_gc_t : std::list<rec_nra_var_t>
|
||||||
|
{
|
||||||
|
rec_nra_gc_t() = default;
|
||||||
|
rec_nra_gc_t(std::initializer_list<rec_nra_var_t> l) : std::list<rec_nra_var_t>(l) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace boost { namespace geometry { namespace traits {
|
||||||
|
template<> struct tag<rec_gc_t> { typedef geometry_collection_tag type; };
|
||||||
|
template<> struct geometry_types<rec_gc_t> { typedef util::type_sequence<point_t, linestring_t, rec_gc_t, polygon_t> type; };
|
||||||
|
}}}
|
||||||
|
|
||||||
|
namespace boost { namespace geometry { namespace traits {
|
||||||
|
template<> struct tag<rec_nra_gc_t> { typedef geometry_collection_tag type; };
|
||||||
|
template<> struct geometry_types<rec_nra_gc_t> { typedef util::type_sequence<point_t, linestring_t, rec_nra_gc_t, polygon_t> type; };
|
||||||
|
}}}
|
||||||
|
|
||||||
|
template <typename GC>
|
||||||
|
GC make_gc()
|
||||||
|
{
|
||||||
|
return GC{
|
||||||
|
point_t{0, 0},
|
||||||
|
linestring_t{{1, 1}, {2, 2}},
|
||||||
|
polygon_t{{{3, 3}, {3, 4}, {4, 4}, {4, 3}, {3, 3}}},
|
||||||
|
polygon_t{{{5, 5}, {5, 6}, {6, 6}, {6, 5}, {5, 5}}}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename GC>
|
||||||
|
GC make_rec_gc()
|
||||||
|
{
|
||||||
|
return GC{
|
||||||
|
point_t{0, 0},
|
||||||
|
GC {
|
||||||
|
// This should be put at the end because GC is processed in a BFS manner.
|
||||||
|
// So both GCs should be equivalent.
|
||||||
|
polygon_t{{{5, 5}, {5, 6}, {6, 6}, {6, 5}, {5, 5}}}
|
||||||
|
},
|
||||||
|
linestring_t{{1, 1}, {2, 2}},
|
||||||
|
polygon_t{{{3, 3}, {3, 4}, {4, 4}, {4, 3}, {3, 3}}},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename GC, typename Make>
|
||||||
|
void test_all(Make make)
|
||||||
|
{
|
||||||
|
using view_t = bg::detail::random_access_view<GC>;
|
||||||
|
|
||||||
|
GC gc = make();
|
||||||
|
view_t rav{gc};
|
||||||
|
|
||||||
|
using non_gc_types = bg::util::type_sequence<point_t, linestring_t, polygon_t>;
|
||||||
|
using view_types = typename bg::traits::geometry_types<view_t>::type;
|
||||||
|
BOOST_STATIC_ASSERT((std::is_same<non_gc_types, view_types>::value));
|
||||||
|
BOOST_STATIC_ASSERT(bg::detail::is_random_access_range<view_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(! bg::detail::is_geometry_collection_recursive<view_t>::value);
|
||||||
|
|
||||||
|
size_t s = boost::size(gc);
|
||||||
|
for (size_t i = 0 ; i < s ; ++i)
|
||||||
|
{
|
||||||
|
bg::traits::iter_visit<bg::detail::random_access_view<GC>>::apply([&](auto&& g)
|
||||||
|
{
|
||||||
|
using geom_t = bg::util::remove_cref_t<decltype(g)>;
|
||||||
|
if (i == 0) { BOOST_CHECK(bg::util::is_point<geom_t>::value); }
|
||||||
|
else if (i == 1) { BOOST_CHECK(bg::util::is_linestring<geom_t>::value); }
|
||||||
|
else { BOOST_CHECK(bg::util::is_polygon<geom_t>::value); }
|
||||||
|
}, rav.begin() + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main(int, char* [])
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(bg::detail::is_random_access_range<gc_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(! bg::detail::is_random_access_range<nra_gc_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(bg::detail::is_random_access_range<rec_gc_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(! bg::detail::is_random_access_range<rec_nra_gc_t>::value);
|
||||||
|
|
||||||
|
BOOST_STATIC_ASSERT(! bg::detail::is_geometry_collection_recursive<gc_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(! bg::detail::is_geometry_collection_recursive<nra_gc_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(bg::detail::is_geometry_collection_recursive<rec_gc_t>::value);
|
||||||
|
BOOST_STATIC_ASSERT(bg::detail::is_geometry_collection_recursive<rec_nra_gc_t>::value);
|
||||||
|
|
||||||
|
test_all<gc_t>(make_gc<gc_t>);
|
||||||
|
test_all<nra_gc_t>(make_gc<nra_gc_t>);
|
||||||
|
test_all<rec_gc_t>(make_gc<rec_gc_t>);
|
||||||
|
test_all<rec_nra_gc_t>(make_gc<rec_nra_gc_t>);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user