summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/difference.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/difference.hpp')
-rw-r--r--boost/geometry/algorithms/difference.hpp449
1 files changed, 314 insertions, 135 deletions
diff --git a/boost/geometry/algorithms/difference.hpp b/boost/geometry/algorithms/difference.hpp
index 2155b9e546..ec6e4ea734 100644
--- a/boost/geometry/algorithms/difference.hpp
+++ b/boost/geometry/algorithms/difference.hpp
@@ -2,9 +2,9 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2017-2021.
-// Modifications copyright (c) 2017-2021, Oracle and/or its affiliates.
-
+// This file was modified by Oracle on 2017-2023.
+// Modifications copyright (c) 2017-2023, Oracle and/or its affiliates.
+// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
@@ -15,19 +15,21 @@
#define BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-#include <boost/variant/variant_fwd.hpp>
-
+#include <boost/geometry/algorithms/detail/gc_make_rtree.hpp>
+#include <boost/geometry/algorithms/detail/intersection/gc.hpp>
#include <boost/geometry/algorithms/detail/intersection/multi.hpp>
#include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
+#include <boost/geometry/algorithms/detail/visit.hpp>
+#include <boost/geometry/core/geometry_types.hpp>
+#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/policies/robustness/get_rescale_policy.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/util/range.hpp>
+#include <boost/geometry/util/sequence.hpp>
+#include <boost/geometry/views/detail/geometry_collection_view.hpp>
namespace boost { namespace geometry
@@ -37,14 +39,23 @@ namespace boost { namespace geometry
namespace detail { namespace difference
{
+
+// True if the result of difference can be different than Geometry1
+template <typename Geometry1, typename Geometry2>
+using is_subtractable_t = util::bool_constant
+ <
+ (geometry::topological_dimension<Geometry1>::value
+ <= geometry::topological_dimension<Geometry2>::value)
+ >;
+
+
template
<
typename Geometry1,
typename Geometry2,
typename SingleOut,
typename OutTag = typename detail::setop_insert_output_tag<SingleOut>::type,
- bool ReturnGeometry1 = (topological_dimension<Geometry1>::value
- > topological_dimension<Geometry2>::value)
+ bool ReturnGeometry1 = (! is_subtractable_t<Geometry1, Geometry2>::value)
>
struct call_intersection_insert
{
@@ -71,6 +82,26 @@ struct call_intersection_insert
}
};
+
+template <typename Geometry1, typename Geometry2, typename SingleOut, typename OutTag>
+struct call_intersection_insert<Geometry1, Geometry2, SingleOut, OutTag, true>
+{
+ template <typename OutputIterator, typename RobustPolicy, typename Strategy>
+ static inline OutputIterator apply(Geometry1 const& geometry1,
+ Geometry2 const& ,
+ RobustPolicy const& ,
+ OutputIterator out,
+ Strategy const& )
+ {
+ return geometry::detail::convert_to_output
+ <
+ Geometry1,
+ SingleOut
+ >::apply(geometry1, out);
+ }
+};
+
+
template
<
typename Geometry1,
@@ -268,10 +299,237 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1,
}
+template
+<
+ typename Geometry, typename Collection,
+ typename CastedTag = typename geometry::tag_cast
+ <
+ typename geometry::tag<Geometry>::type,
+ pointlike_tag, linear_tag, areal_tag
+ >::type
+>
+struct multi_output_type
+{
+ BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
+ "Not implemented this Geometry type.",
+ Geometry, CastedTag);
+};
+
+template <typename Geometry, typename Collection>
+struct multi_output_type<Geometry, Collection, pointlike_tag>
+{
+ using type = typename util::sequence_find_if
+ <
+ typename traits::geometry_types<Collection>::type,
+ util::is_multi_point
+ >::type;
+};
+
+template <typename Geometry, typename Collection>
+struct multi_output_type<Geometry, Collection, linear_tag>
+{
+ using type = typename util::sequence_find_if
+ <
+ typename traits::geometry_types<Collection>::type,
+ util::is_multi_linestring
+ >::type;
+};
+
+template <typename Geometry, typename Collection>
+struct multi_output_type<Geometry, Collection, areal_tag>
+{
+ using type = typename util::sequence_find_if
+ <
+ typename traits::geometry_types<Collection>::type,
+ util::is_multi_polygon
+ >::type;
+};
+
+
}} // namespace detail::difference
#endif // DOXYGEN_NO_DETAIL
+namespace resolve_collection
+{
+
+
+template
+<
+ typename Geometry1, typename Geometry2, typename Collection,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type,
+ typename CollectionTag = typename geometry::tag<Collection>::type
+>
+struct difference
+{
+ template <typename Strategy>
+ static void apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Collection & output_collection,
+ Strategy const& strategy)
+ {
+ using single_out = typename geometry::detail::output_geometry_value
+ <
+ Collection
+ >::type;
+
+ detail::difference::difference_insert<single_out>(
+ geometry1, geometry2,
+ geometry::detail::output_geometry_back_inserter(output_collection),
+ strategy);
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Collection>
+struct difference
+ <
+ Geometry1, Geometry2, Collection,
+ geometry_collection_tag, geometry_collection_tag, geometry_collection_tag
+ >
+{
+ template <typename Strategy>
+ static void apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Collection& output_collection,
+ Strategy const& strategy)
+ {
+ auto const rtree2 = detail::gc_make_rtree_iterators(geometry2, strategy);
+ detail::visit_breadth_first([&](auto const& g1)
+ {
+ // multi-point, multi-linestring or multi_polygon
+ typename detail::difference::multi_output_type
+ <
+ util::remove_cref_t<decltype(g1)>, Collection
+ >::type out;
+
+ g1_minus_gc2(g1, rtree2, out, strategy);
+
+ detail::intersection::gc_move_multi_back(output_collection, out);
+
+ return true;
+ }, geometry1);
+ }
+
+private:
+ // Implemented as separate function because msvc is unable to do nested lambda capture
+ template <typename G1, typename Rtree2, typename MultiOut, typename Strategy>
+ static void g1_minus_gc2(G1 const& g1, Rtree2 const& rtree2, MultiOut& out, Strategy const& strategy)
+ {
+ {
+ using single_out_t = typename geometry::detail::output_geometry_value<MultiOut>::type;
+ auto out_it = geometry::detail::output_geometry_back_inserter(out);
+ geometry::detail::convert_to_output<G1, single_out_t>::apply(g1, out_it);
+ }
+
+ using box1_t = detail::gc_make_rtree_box_t<G1>;
+ box1_t b1 = geometry::return_envelope<box1_t>(g1, strategy);
+ detail::expand_by_epsilon(b1);
+
+ for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit)
+ {
+ traits::iter_visit<Geometry2>::apply([&](auto const& g2)
+ {
+ multi_out_minus_g2(out, g2, strategy);
+ }, qit->second);
+
+ if (boost::empty(out))
+ {
+ return;
+ }
+ }
+ }
+
+ template
+ <
+ typename MultiOut, typename G2, typename Strategy,
+ std::enable_if_t<detail::difference::is_subtractable_t<MultiOut, G2>::value, int> = 0
+ >
+ static void multi_out_minus_g2(MultiOut& out, G2 const& g2, Strategy const& strategy)
+ {
+ MultiOut result;
+ difference<MultiOut, G2, MultiOut>::apply(out, g2, result, strategy);
+ out = std::move(result);
+ }
+
+ template
+ <
+ typename MultiOut, typename G2, typename Strategy,
+ std::enable_if_t<(! detail::difference::is_subtractable_t<MultiOut, G2>::value), int> = 0
+ >
+ static void multi_out_minus_g2(MultiOut& , G2 const& , Strategy const& )
+ {}
+};
+
+
+template <typename Geometry1, typename Geometry2, typename Collection, typename Tag1>
+struct difference
+ <
+ Geometry1, Geometry2, Collection,
+ Tag1, geometry_collection_tag, geometry_collection_tag
+ >
+{
+ template <typename Strategy>
+ static void apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Collection & output_collection,
+ Strategy const& strategy)
+ {
+ using gc_view_t = geometry::detail::geometry_collection_view<Geometry1>;
+ difference
+ <
+ gc_view_t, Geometry2, Collection
+ >::apply(gc_view_t(geometry1), geometry2, output_collection, strategy);
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Collection, typename Tag2>
+struct difference
+ <
+ Geometry1, Geometry2, Collection,
+ geometry_collection_tag, Tag2, geometry_collection_tag
+ >
+{
+ template <typename Strategy>
+ static void apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Collection & output_collection,
+ Strategy const& strategy)
+ {
+ using gc_view_t = geometry::detail::geometry_collection_view<Geometry2>;
+ difference
+ <
+ Geometry1, gc_view_t, Collection
+ >::apply(geometry1, gc_view_t(geometry2), output_collection, strategy);
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Collection, typename Tag1, typename Tag2>
+struct difference
+ <
+ Geometry1, Geometry2, Collection,
+ Tag1, Tag2, geometry_collection_tag
+ >
+{
+ template <typename Strategy>
+ static void apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Collection & output_collection,
+ Strategy const& strategy)
+ {
+ using gc1_view_t = geometry::detail::geometry_collection_view<Geometry1>;
+ using gc2_view_t = geometry::detail::geometry_collection_view<Geometry2>;
+ difference
+ <
+ gc1_view_t, gc2_view_t, Collection
+ >::apply(gc1_view_t(geometry1), gc2_view_t(geometry2), output_collection, strategy);
+ }
+};
+
+
+} // namespace resolve_collection
+
+
namespace resolve_strategy {
template
@@ -287,15 +545,10 @@ struct difference
Collection & output_collection,
Strategy const& strategy)
{
- typedef typename geometry::detail::output_geometry_value
+ resolve_collection::difference
<
- Collection
- >::type single_out;
-
- detail::difference::difference_insert<single_out>(
- geometry1, geometry2,
- geometry::detail::output_geometry_back_inserter(output_collection),
- strategy);
+ Geometry1, Geometry2, Collection
+ >::apply(geometry1, geometry2, output_collection, strategy);
}
};
@@ -309,7 +562,7 @@ struct difference<Strategy, false>
Strategy const& strategy)
{
using strategies::relate::services::strategy_converter;
-
+
difference
<
decltype(strategy_converter<Strategy>::get(strategy))
@@ -332,7 +585,7 @@ struct difference<default_strategy, false>
Geometry1,
Geometry2
>::type strategy_type;
-
+
difference
<
strategy_type
@@ -343,17 +596,20 @@ struct difference<default_strategy, false>
} // resolve_strategy
-namespace resolve_variant
+namespace resolve_dynamic
{
-
-template <typename Geometry1, typename Geometry2>
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1 = typename geometry::tag<Geometry1>::type,
+ typename Tag2 = typename geometry::tag<Geometry2>::type
+>
struct difference
{
template <typename Collection, typename Strategy>
- static inline void apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Collection& output_collection,
- Strategy const& strategy)
+ static void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Collection& output_collection, Strategy const& strategy)
{
resolve_strategy::difference
<
@@ -362,135 +618,58 @@ struct difference
}
};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
-struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
+struct difference<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2>
{
template <typename Collection, typename Strategy>
- struct visitor: static_visitor<>
+ static void apply(DynamicGeometry1 const& geometry1, Geometry2 const& geometry2,
+ Collection& output_collection, Strategy const& strategy)
{
- Geometry2 const& m_geometry2;
- Collection& m_output_collection;
- Strategy const& m_strategy;
-
- visitor(Geometry2 const& geometry2,
- Collection& output_collection,
- Strategy const& strategy)
- : m_geometry2(geometry2)
- , m_output_collection(output_collection)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry1>
- void operator()(Geometry1 const& geometry1) const
+ traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
{
- difference
+ resolve_strategy::difference
<
- Geometry1,
- Geometry2
- >::apply(geometry1, m_geometry2, m_output_collection, m_strategy);
- }
- };
-
- template <typename Collection, typename Strategy>
- static inline void
- apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
- Geometry2 const& geometry2,
- Collection& output_collection,
- Strategy const& strategy)
- {
- boost::apply_visitor(visitor<Collection, Strategy>(geometry2,
- output_collection,
- strategy),
- geometry1);
+ Strategy
+ >::apply(g1, geometry2, output_collection, strategy);
+ }, geometry1);
}
};
-
-template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
+struct difference<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag>
{
template <typename Collection, typename Strategy>
- struct visitor: static_visitor<>
+ static void apply(Geometry1 const& geometry1, DynamicGeometry2 const& geometry2,
+ Collection& output_collection, Strategy const& strategy)
{
- Geometry1 const& m_geometry1;
- Collection& m_output_collection;
- Strategy const& m_strategy;
-
- visitor(Geometry1 const& geometry1,
- Collection& output_collection,
- Strategy const& strategy)
- : m_geometry1(geometry1)
- , m_output_collection(output_collection)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry2>
- void operator()(Geometry2 const& geometry2) const
+ traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
{
- difference
+ resolve_strategy::difference
<
- Geometry1,
- Geometry2
- >::apply(m_geometry1, geometry2, m_output_collection, m_strategy);
- }
- };
-
- template <typename Collection, typename Strategy>
- static inline void
- apply(Geometry1 const& geometry1,
- variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
- Collection& output_collection,
- Strategy const& strategy)
- {
- boost::apply_visitor(visitor<Collection, Strategy>(geometry1,
- output_collection,
- strategy),
- geometry2);
+ Strategy
+ >::apply(geometry1, g2, output_collection, strategy);
+ }, geometry2);
}
};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
-struct difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
+template <typename DynamicGeometry1, typename DynamicGeometry2>
+struct difference<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag>
{
template <typename Collection, typename Strategy>
- struct visitor: static_visitor<>
+ static void apply(DynamicGeometry1 const& geometry1, DynamicGeometry2 const& geometry2,
+ Collection& output_collection, Strategy const& strategy)
{
- Collection& m_output_collection;
- Strategy const& m_strategy;
-
- visitor(Collection& output_collection, Strategy const& strategy)
- : m_output_collection(output_collection)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry1, typename Geometry2>
- void operator()(Geometry1 const& geometry1,
- Geometry2 const& geometry2) const
+ traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
{
- difference
+ resolve_strategy::difference
<
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, m_output_collection, m_strategy);
- }
- };
-
- template <typename Collection, typename Strategy>
- static inline void
- apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
- variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
- Collection& output_collection,
- Strategy const& strategy)
- {
- boost::apply_visitor(visitor<Collection, Strategy>(output_collection,
- strategy),
- geometry1, geometry2);
+ Strategy
+ >::apply(g1, g2, output_collection, strategy);
+ }, geometry1, geometry2);
}
};
-
-} // namespace resolve_variant
+
+} // namespace resolve_dynamic
/*!
@@ -521,7 +700,7 @@ inline void difference(Geometry1 const& geometry1,
Collection& output_collection,
Strategy const& strategy)
{
- resolve_variant::difference
+ resolve_dynamic::difference
<
Geometry1,
Geometry2
@@ -552,7 +731,7 @@ inline void difference(Geometry1 const& geometry1,
Geometry2 const& geometry2,
Collection& output_collection)
{
- resolve_variant::difference
+ resolve_dynamic::difference
<
Geometry1,
Geometry2