[intersection] Modify tupled-output utils and move them out from intersection code.

This commit is contained in:
Adam Wulkiewicz
2020-04-13 15:54:46 +02:00
parent 2dbe5bf554
commit 670c52d3e3
4 changed files with 348 additions and 152 deletions

View File

@@ -26,7 +26,7 @@ namespace detail { namespace intersection
template
<
typename GeometryOut,
typename OutTag = typename detail::intersection::tag
typename OutTag = typename geometry::detail::setop_insert_output_tag
<
typename geometry::detail::output_geometry_value
<
@@ -85,9 +85,10 @@ struct intersection_areal_areal_<TupledOut, tupled_output_tag>
boost::ignore_unused
<
detail::intersection::expect_output_pla
geometry::detail::expect_output
<
Areal1, Areal2, single_out
Areal1, Areal2, single_out,
point_tag, linestring_tag, polygon_tag
>
>();

View File

@@ -432,8 +432,8 @@ struct intersection_insert
TupledOut,
OverlayType,
ReverseMultiLinestring, ReverseRing,
multi_linestring_tag, ring_tag, detail::intersection::tupled_output_tag,
linear_tag, areal_tag, detail::intersection::tupled_output_tag
multi_linestring_tag, ring_tag, detail::tupled_output_tag,
linear_tag, areal_tag, detail::tupled_output_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseRing,
@@ -441,7 +441,19 @@ struct intersection_insert
OverlayType,
true
>
, detail::intersection::expect_output_pl<MultiLinestring, Ring, TupledOut>
, detail::expect_output
<
MultiLinestring, Ring, TupledOut,
// NOTE: points can be the result only in case of intersection.
// TODO: union should require L and A
typename boost::mpl::if_c
<
(OverlayType == overlay_intersection),
point_tag,
void
>::type,
linestring_tag
>
{};
@@ -458,8 +470,8 @@ struct intersection_insert
TupledOut,
OverlayType,
ReverseMultiLinestring, ReversePolygon,
multi_linestring_tag, polygon_tag, detail::intersection::tupled_output_tag,
linear_tag, areal_tag, detail::intersection::tupled_output_tag
multi_linestring_tag, polygon_tag, detail::tupled_output_tag,
linear_tag, areal_tag, detail::tupled_output_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReversePolygon,
@@ -467,7 +479,19 @@ struct intersection_insert
OverlayType,
true
>
, detail::intersection::expect_output_pl<MultiLinestring, Polygon, TupledOut>
, detail::expect_output
<
MultiLinestring, Polygon, TupledOut,
// NOTE: points can be the result only in case of intersection.
// TODO: union should require L and A
typename boost::mpl::if_c
<
(OverlayType == overlay_intersection),
point_tag,
void
>::type,
linestring_tag
>
{};
template
@@ -483,8 +507,8 @@ struct intersection_insert
TupledOut,
OverlayType,
ReversePolygon, ReverseMultiLinestring,
polygon_tag, multi_linestring_tag, detail::intersection::tupled_output_tag,
areal_tag, linear_tag, detail::intersection::tupled_output_tag
polygon_tag, multi_linestring_tag, detail::tupled_output_tag,
areal_tag, linear_tag, detail::tupled_output_tag
> : detail::intersection::intersection_of_areal_with_multi_linestring
<
ReversePolygon,
@@ -492,7 +516,22 @@ struct intersection_insert
OverlayType,
true
>
, detail::intersection::expect_output_pl<Polygon, MultiLinestring, TupledOut>
, detail::expect_output
<
Polygon, MultiLinestring, TupledOut,
// NOTE: points can be the result only in case of intersection.
// TODO: union should require L and A
// TODO: in general the result of difference should depend on the first argument
// but this specialization calls L/A in reality so the first argument is linear.
// So expect only L for difference?
typename boost::mpl::if_c
<
(OverlayType == overlay_intersection),
point_tag,
void
>::type,
linestring_tag
>
{};
template
@@ -508,8 +547,8 @@ struct intersection_insert
TupledOut,
OverlayType,
ReverseMultiLinestring, ReverseMultiPolygon,
multi_linestring_tag, multi_polygon_tag, detail::intersection::tupled_output_tag,
linear_tag, areal_tag, detail::intersection::tupled_output_tag
multi_linestring_tag, multi_polygon_tag, detail::tupled_output_tag,
linear_tag, areal_tag, detail::tupled_output_tag
> : detail::intersection::intersection_of_multi_linestring_with_areal
<
ReverseMultiPolygon,
@@ -517,7 +556,19 @@ struct intersection_insert
OverlayType,
true
>
, detail::intersection::expect_output_pl<MultiLinestring, MultiPolygon, TupledOut>
, detail::expect_output
<
MultiLinestring, MultiPolygon, TupledOut,
// NOTE: points can be the result only in case of intersection.
// TODO: union should require L and A
typename boost::mpl::if_c
<
(OverlayType == overlay_intersection),
point_tag,
void
>::type,
linestring_tag
>
{};

View File

@@ -525,73 +525,6 @@ struct intersection_areal_linear_point
};
struct tupled_output_tag {};
template
<
typename GeometryOut,
bool IsTupled = geometry::detail::is_tupled_range_values<GeometryOut>::value
>
struct tag
: geometry::tag<GeometryOut>
{};
template <typename GeometryOut>
struct tag<GeometryOut, true>
{
typedef tupled_output_tag type;
};
template <typename Geometry1, typename Geometry2, typename TupledOut>
struct expect_output_p
{
static const bool is_point_found = geometry::tuples::exists_if
<
TupledOut, geometry::detail::is_tag_same_as_pred<point_tag>::template pred
>::value;
BOOST_MPL_ASSERT_MSG
(
is_point_found, POINTLIKE_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
(types<Geometry1, Geometry2, TupledOut>)
);
};
template <typename Geometry1, typename Geometry2, typename TupledOut>
struct expect_output_pl
: expect_output_p<Geometry1, Geometry2, TupledOut>
{
static const bool is_linestring_found = geometry::tuples::exists_if
<
TupledOut, geometry::detail::is_tag_same_as_pred<linestring_tag>::template pred
>::value;
BOOST_MPL_ASSERT_MSG
(
is_linestring_found, LINEAR_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
(types<Geometry1, Geometry2, TupledOut>)
);
};
template <typename Geometry1, typename Geometry2, typename TupledOut>
struct expect_output_pla
: expect_output_pl<Geometry1, Geometry2, TupledOut>
{
static const bool is_polygon_found = geometry::tuples::exists_if
<
TupledOut, geometry::detail::is_tag_same_as_pred<polygon_tag>::template pred
>::value;
BOOST_MPL_ASSERT_MSG
(
is_polygon_found, AREAL_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
(types<Geometry1, Geometry2, TupledOut>)
);
};
}} // namespace detail::intersection
#endif // DOXYGEN_NO_DETAIL
@@ -614,7 +547,7 @@ template
// tag dispatching:
typename TagIn1 = typename geometry::tag<Geometry1>::type,
typename TagIn2 = typename geometry::tag<Geometry2>::type,
typename TagOut = typename detail::intersection::tag<GeometryOut>::type,
typename TagOut = typename detail::setop_insert_output_tag<GeometryOut>::type,
// metafunction finetuning helpers:
typename CastedTagIn1 = typename geometry::tag_cast<TagIn1, areal_tag, linear_tag, pointlike_tag>::type,
typename CastedTagIn2 = typename geometry::tag_cast<TagIn2, areal_tag, linear_tag, pointlike_tag>::type,
@@ -996,13 +929,21 @@ struct intersection_insert
<
Linear1, Linear2, TupledOut, OverlayType,
Reverse1, Reverse2,
TagIn1, TagIn2, detail::intersection::tupled_output_tag,
linear_tag, linear_tag, detail::intersection::tupled_output_tag
TagIn1, TagIn2, detail::tupled_output_tag,
linear_tag, linear_tag, detail::tupled_output_tag
>
// NOTE: This is not fully correct because points can be the result only in
// case of intersection but intersection_insert is called also by difference.
// So this requirement could be relaxed in the future.
: detail::intersection::expect_output_pl<Linear1, Linear2, TupledOut>
: detail::expect_output
<
Linear1, Linear2, TupledOut,
// NOTE: points can be the result only in case of intersection.
typename boost::mpl::if_c
<
(OverlayType == overlay_intersection),
point_tag,
void
>::type,
linestring_tag
>
{
// NOTE: The order of geometries in TupledOut tuple/pair must correspond to the order
// iterators in OutputIterators tuple/pair.
@@ -1113,10 +1054,10 @@ struct intersection_insert
<
PointLike1, PointLike2, TupledOut, OverlayType,
Reverse1, Reverse2,
TagIn1, TagIn2, detail::intersection::tupled_output_tag,
pointlike_tag, pointlike_tag, detail::intersection::tupled_output_tag
TagIn1, TagIn2, detail::tupled_output_tag,
pointlike_tag, pointlike_tag, detail::tupled_output_tag
>
: detail::intersection::expect_output_p<PointLike1, PointLike2, TupledOut>
: detail::expect_output<PointLike1, PointLike2, TupledOut, point_tag>
{
// NOTE: The order of geometries in TupledOut tuple/pair must correspond to the order
// of iterators in OutputIterators tuple/pair.
@@ -1240,16 +1181,16 @@ struct intersection_insert
<
PointLike, Linear, TupledOut, OverlayType,
Reverse1, Reverse2,
TagIn1, TagIn2, detail::intersection::tupled_output_tag,
pointlike_tag, linear_tag, detail::intersection::tupled_output_tag
TagIn1, TagIn2, detail::tupled_output_tag,
pointlike_tag, linear_tag, detail::tupled_output_tag
>
// Reuse the implementation for PointLike/PointLike.
: intersection_insert
<
PointLike, Linear, TupledOut, OverlayType,
Reverse1, Reverse2,
TagIn1, TagIn2, detail::intersection::tupled_output_tag,
pointlike_tag, pointlike_tag, detail::intersection::tupled_output_tag
TagIn1, TagIn2, detail::tupled_output_tag,
pointlike_tag, pointlike_tag, detail::tupled_output_tag
>
{};
@@ -1265,8 +1206,8 @@ struct intersection_insert
<
Linestring, MultiPoint, TupledOut, overlay_intersection,
Reverse1, Reverse2,
linestring_tag, multi_point_tag, detail::intersection::tupled_output_tag,
linear_tag, pointlike_tag, detail::intersection::tupled_output_tag
linestring_tag, multi_point_tag, detail::tupled_output_tag,
linear_tag, pointlike_tag, detail::tupled_output_tag
>
{
template <typename RobustPolicy, typename OutputIterators, typename Strategy>
@@ -1368,16 +1309,16 @@ struct intersection_insert
<
PointLike, Areal, TupledOut, OverlayType,
Reverse1, Reverse2,
TagIn1, TagIn2, detail::intersection::tupled_output_tag,
pointlike_tag, areal_tag, detail::intersection::tupled_output_tag
TagIn1, TagIn2, detail::tupled_output_tag,
pointlike_tag, areal_tag, detail::tupled_output_tag
>
// Reuse the implementation for PointLike/PointLike.
: intersection_insert
<
PointLike, Areal, TupledOut, OverlayType,
Reverse1, Reverse2,
TagIn1, TagIn2, detail::intersection::tupled_output_tag,
pointlike_tag, pointlike_tag, detail::intersection::tupled_output_tag
TagIn1, TagIn2, detail::tupled_output_tag,
pointlike_tag, pointlike_tag, detail::tupled_output_tag
>
{};
@@ -1394,8 +1335,8 @@ struct intersection_insert
<
Areal, MultiPoint, TupledOut, overlay_intersection,
Reverse1, Reverse2,
TagIn1, multi_point_tag, detail::intersection::tupled_output_tag,
areal_tag, pointlike_tag, detail::intersection::tupled_output_tag
TagIn1, multi_point_tag, detail::tupled_output_tag,
areal_tag, pointlike_tag, detail::tupled_output_tag
>
{
template <typename RobustPolicy, typename OutputIterators, typename Strategy>
@@ -1426,8 +1367,8 @@ struct intersection_insert
TupledOut,
OverlayType,
ReverseLinestring, ReversePolygon,
linestring_tag, polygon_tag, detail::intersection::tupled_output_tag,
linear_tag, areal_tag, detail::intersection::tupled_output_tag
linestring_tag, polygon_tag, detail::tupled_output_tag,
linear_tag, areal_tag, detail::tupled_output_tag
> : detail::intersection::intersection_of_linestring_with_areal
<
ReversePolygon,
@@ -1450,8 +1391,8 @@ struct intersection_insert
TupledOut,
OverlayType,
ReverseLinestring, ReverseRing,
linestring_tag, ring_tag, detail::intersection::tupled_output_tag,
linear_tag, areal_tag, detail::intersection::tupled_output_tag
linestring_tag, ring_tag, detail::tupled_output_tag,
linear_tag, areal_tag, detail::tupled_output_tag
> : detail::intersection::intersection_of_linestring_with_areal
<
ReverseRing,

View File

@@ -9,13 +9,17 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/core/config.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tag_cast.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/util/tuples.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/if.hpp>
#include <boost/range/value_type.hpp>
#include <boost/type_traits/detail/yes_no_type.hpp>
#include <boost/type_traits/integral_constant.hpp>
@@ -53,7 +57,7 @@ struct is_multi_geometry
// true for point, linestring or polygon
template <typename T>
struct is_multi_geometry_value
struct is_multi_geometry_element
: boost::integral_constant
<
bool,
@@ -86,23 +90,6 @@ struct is_range
{};
// geometry tag of Rng value_type
template <typename Rng>
struct range_value_tag
: geometry::tag<typename boost::range_value<Rng>::type>
{};
// true if geometry tag of Rng is the same as Tag
template <typename Rng, typename Tag>
struct is_range_value_tag_same_as
: boost::is_same
<
typename range_value_tag<Rng>::type,
Tag
>
{};
template <typename T, bool IsRange = is_range<T>::value>
struct is_tupled_output_element_base
: boost::integral_constant<bool, false>
@@ -114,12 +101,13 @@ struct is_tupled_output_element_base<T, true>
<
bool,
(is_multi_geometry<T>::value
||
((! is_geometry<T>::value)
&&
((is_range_value_tag_same_as<T, point_tag>::value)
|| (is_range_value_tag_same_as<T, linestring_tag>::value)
|| (is_range_value_tag_same_as<T, polygon_tag>::value))))
||
((! is_geometry<T>::value)
&&
is_multi_geometry_element
<
typename boost::range_value<T>::type
>::value))
>
{};
@@ -134,7 +122,7 @@ struct is_tupled_output_element
// true if Output is not a geometry (so e.g. tuple was not adapted to any
// concept) and at least one of the tuple elements is a multi-geometry or
// a range of points linestrings or polygons
// a range of points, linestrings or polygons
template <typename Output>
struct is_tupled_output_check
: boost::mpl::and_
@@ -146,28 +134,15 @@ struct is_tupled_output_check
{};
// true if T is a point, linestring or polygon
template <typename T>
struct is_tupled_range_values_element
: boost::integral_constant
<
bool,
((boost::is_same<typename geometry::tag<T>::type, point_tag>::value)
|| (boost::is_same<typename geometry::tag<T>::type, linestring_tag>::value)
|| (boost::is_same<typename geometry::tag<T>::type, polygon_tag>::value))
>
{};
// true if T is not a geometry (so e.g. tuple was not adapted to any
// concept) and at least one of the tuple elements is a point, linesting
// or polygon
template <typename T>
struct is_tupled_range_values_check
struct is_tupled_single_output_check
: boost::mpl::and_
<
boost::is_same<typename geometry::tag<T>::type, void>,
geometry::tuples::exists_if<T, is_tupled_range_values_element>
geometry::tuples::exists_if<T, is_multi_geometry_element>
>
{};
@@ -222,15 +197,15 @@ struct is_tupled_output<Output, true>
// true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple
// and is_tupled_range_values_check defiend above passes
// and is_tupled_single_output_check defiend above passes
template <typename T, bool IsTupled = is_tupled<T>::value>
struct is_tupled_range_values
struct is_tupled_single_output
: boost::integral_constant<bool, false>
{};
template <typename T>
struct is_tupled_range_values<T, true>
: is_tupled_range_values_check<T>
struct is_tupled_single_output<T, true>
: is_tupled_single_output_check<T>
{};
@@ -527,6 +502,234 @@ struct output_geometry_access<GeometryOut, Tag, DefaultTag, DefaultTag>
};
template <typename Geometry>
struct output_geometry_concept_check
{
static void apply()
{
concepts::check<Geometry>();
}
};
template <typename First, typename Second>
struct output_geometry_concept_check<std::pair<First, Second> >
{
static void apply()
{
concepts::check<First>();
concepts::check<Second>();
}
};
template <typename Tuple,
size_t I = 0,
size_t N = geometry::tuples::size<Tuple>::value>
struct output_geometry_concept_check_t
{
static void apply()
{
concepts::check<typename geometry::tuples::element<I, Tuple>::type>();
output_geometry_concept_check_t<Tuple, I + 1, N>::apply();
}
};
template <typename Tuple, size_t N>
struct output_geometry_concept_check_t<Tuple, N, N>
{
static void apply()
{}
};
template
<
class T0, class T1, class T2, class T3, class T4,
class T5, class T6, class T7, class T8, class T9
>
struct output_geometry_concept_check<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
: output_geometry_concept_check_t<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
{};
template <typename HT, typename TT>
struct output_geometry_concept_check<boost::tuples::cons<HT, TT> >
: output_geometry_concept_check_t<boost::tuples::cons<HT, TT> >
{};
#ifdef BOOST_GEOMETRY_CXX11_TUPLE
template <typename ...Ts>
struct output_geometry_concept_check<std::tuple<Ts...> >
: output_geometry_concept_check_t<std::tuple<Ts...> >
{};
#endif // BOOST_GEOMETRY_CXX11_TUPLE
struct tupled_output_tag {};
template <typename GeometryOut>
struct setop_insert_output_tag
: boost::mpl::if_c
<
geometry::detail::is_tupled_single_output<GeometryOut>::value,
tupled_output_tag,
typename geometry::tag<GeometryOut>::type
>
{};
template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound, typename Tag>
struct expect_output_assert_base;
template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, pointlike_tag>
{
BOOST_MPL_ASSERT_MSG
(
IsFound, POINTLIKE_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
(types<Geometry1, Geometry2, TupledOut>)
);
};
template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, linear_tag>
{
BOOST_MPL_ASSERT_MSG
(
IsFound, LINEAR_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
(types<Geometry1, Geometry2, TupledOut>)
);
};
template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, areal_tag>
{
BOOST_MPL_ASSERT_MSG
(
IsFound, AREAL_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
(types<Geometry1, Geometry2, TupledOut>)
);
};
template <typename Geometry1, typename Geometry2, typename TupledOut, typename Tag>
struct expect_output_assert
: expect_output_assert_base
<
Geometry1, Geometry2, TupledOut,
geometry::tuples::exists_if
<
TupledOut,
is_tag_same_as_pred<Tag>::template pred
>::value,
typename geometry::tag_cast
<
Tag, pointlike_tag, linear_tag, areal_tag
>::type
>
{};
template <typename Geometry1, typename Geometry2, typename TupledOut>
struct expect_output_assert<Geometry1, Geometry2, TupledOut, void>
{};
template
<
typename Geometry1, typename Geometry2, typename TupledOut,
typename Tag1,
typename Tag2 = void,
typename Tag3 = void
>
struct expect_output
: expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
, expect_output_assert<Geometry1, Geometry2, TupledOut, Tag2>
, expect_output_assert<Geometry1, Geometry2, TupledOut, Tag3>
{};
template
<
typename Geometry1, typename Geometry2, typename TupledOut,
typename Tag1, typename Tag2
>
struct expect_output<Geometry1, Geometry2, TupledOut, Tag1, Tag2, void>
: expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
, expect_output_assert<Geometry1, Geometry2, TupledOut, Tag2>
{};
template
<
typename Geometry1, typename Geometry2, typename TupledOut,
typename Tag1
>
struct expect_output<Geometry1, Geometry2, TupledOut, Tag1, void, void>
: expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
{};
template <typename CastedTag>
struct casted_tag_to_single_tag;
template <>
struct casted_tag_to_single_tag<pointlike_tag>
{
typedef point_tag type;
};
template <>
struct casted_tag_to_single_tag<linear_tag>
{
typedef linestring_tag type;
};
template <>
struct casted_tag_to_single_tag<areal_tag>
{
typedef polygon_tag type;
};
template
<
typename Geometry,
typename SingleOut,
bool IsMulti = geometry::detail::is_multi_geometry<Geometry>::value
>
struct convert_to_output
{
template <typename OutputIterator>
static OutputIterator apply(Geometry const& geometry,
OutputIterator oit)
{
SingleOut single_out;
geometry::convert(geometry, single_out);
*oit++ = single_out;
return oit;
}
};
template
<
typename Geometry,
typename SingleOut
>
struct convert_to_output<Geometry, SingleOut, true>
{
template <typename OutputIterator>
static OutputIterator apply(Geometry const& geometry,
OutputIterator oit)
{
typedef typename boost::range_iterator<Geometry const>::type iterator;
for (iterator it = boost::begin(geometry); it != boost::end(geometry); ++it)
{
SingleOut single_out;
geometry::convert(*it, single_out);
*oit++ = single_out;
}
return oit;
}
};
} // namespace detail
#endif // DOXYGEN_NO_DETAIL