123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP
- #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_IMPLEMENTATION_GC_HPP
- #include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
- #include <boost/geometry/algorithms/detail/relate/interface.hpp>
- #include <boost/geometry/algorithms/difference.hpp>
- #include <boost/geometry/algorithms/intersection.hpp>
- #include <boost/geometry/algorithms/is_empty.hpp>
- #include <boost/geometry/algorithms/union.hpp>
- #include <boost/geometry/geometries/linestring.hpp>
- #include <boost/geometry/geometries/multi_linestring.hpp>
- #include <boost/geometry/geometries/multi_point.hpp>
- #include <boost/geometry/geometries/multi_polygon.hpp>
- #include <boost/geometry/geometries/polygon.hpp>
- #include <boost/geometry/util/condition.hpp>
- #include <boost/geometry/views/detail/geometry_collection_view.hpp>
- namespace boost { namespace geometry
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail { namespace relate
- {
- template <typename Handler>
- struct aa_handler_wrapper
- {
- bool interrupt = false;
- explicit aa_handler_wrapper(Handler& handler)
- : m_handler(handler)
- , m_overwrite_ii(! handler.template may_update<interior, interior, '2'>())
- , m_overwrite_ie(! handler.template may_update<interior, exterior, '2'>())
- , m_overwrite_ei(! handler.template may_update<exterior, interior, '2'>())
- {}
- template <field F1, field F2, char D>
- inline bool may_update() const
- {
- if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii)
- || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie)
- || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei))
- {
- char const c = m_handler.template get<F1, F2>();
- return D > c || c > '9';
- }
- else
- {
- return m_handler.template may_update<F1, F2, D>();
- }
- }
- template <field F1, field F2, char V>
- inline void update()
- {
- if ((BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == interior) && m_overwrite_ii)
- || (BOOST_GEOMETRY_CONDITION(F1 == interior && F2 == exterior) && m_overwrite_ie)
- || (BOOST_GEOMETRY_CONDITION(F1 == exterior && F2 == interior) && m_overwrite_ei))
- {
-
-
- char const c = m_handler.template get<F1, F2>();
-
- if (V > c || c > '9')
- {
-
- m_handler.template set<F1, F2, V>();
- }
- }
- else
- {
- m_handler.template update<F1, F2, V>();
- }
- interrupt = interrupt || m_handler.interrupt;
- }
- private:
- Handler & m_handler;
- bool const m_overwrite_ii;
- bool const m_overwrite_ie;
- bool const m_overwrite_ei;
- };
- template <typename Geometry1, typename Geometry2>
- struct gc_gc
- {
- static const bool interruption_enabled = true;
- using mpt1_found_t = typename util::sequence_find_if
- <
- typename traits::geometry_types<Geometry1>::type,
- util::is_multi_point
- >::type;
- using mls1_found_t = typename util::sequence_find_if
- <
- typename traits::geometry_types<Geometry1>::type,
- util::is_multi_linestring
- >::type;
- using mpo1_found_t = typename util::sequence_find_if
- <
- typename traits::geometry_types<Geometry1>::type,
- util::is_multi_polygon
- >::type;
- using pt1_t = typename geometry::point_type<Geometry1>::type;
- using mpt1_t = std::conditional_t
- <
- std::is_void<mpt1_found_t>::value,
- geometry::model::multi_point<pt1_t>,
- mpt1_found_t
- >;
- using mls1_t = std::conditional_t
- <
- std::is_void<mls1_found_t>::value,
- geometry::model::multi_linestring<geometry::model::linestring<pt1_t>>,
- mls1_found_t
- >;
- using mpo1_t = std::conditional_t
- <
- std::is_void<mpo1_found_t>::value,
- geometry::model::multi_polygon<geometry::model::polygon<pt1_t>>,
- mpo1_found_t
- >;
- using tuple1_t = boost::tuple<mpt1_t, mls1_t, mpo1_t>;
- using mpt2_found_t = typename util::sequence_find_if
- <
- typename traits::geometry_types<Geometry2>::type,
- util::is_multi_point
- >::type;
- using mls2_found_t = typename util::sequence_find_if
- <
- typename traits::geometry_types<Geometry2>::type,
- util::is_multi_linestring
- >::type;
- using mpo2_found_t = typename util::sequence_find_if
- <
- typename traits::geometry_types<Geometry2>::type,
- util::is_multi_polygon
- >::type;
- using pt2_t = typename geometry::point_type<Geometry2>::type;
- using mpt2_t = std::conditional_t
- <
- std::is_void<mpt2_found_t>::value,
- geometry::model::multi_point<pt2_t>,
- mpt2_found_t
- >;
- using mls2_t = std::conditional_t
- <
- std::is_void<mls2_found_t>::value,
- geometry::model::multi_linestring<geometry::model::linestring<pt2_t>>,
- mls2_found_t
- >;
- using mpo2_t = std::conditional_t
- <
- std::is_void<mpo2_found_t>::value,
- geometry::model::multi_polygon<geometry::model::polygon<pt2_t>>,
- mpo2_found_t
- >;
- using tuple2_t = boost::tuple<mpt2_t, mls2_t, mpo2_t>;
- template <typename Geometry>
- using kind_id = util::index_constant
- <
- util::is_areal<Geometry>::value ? 2
- : util::is_linear<Geometry>::value ? 1
- : 0
- >;
- template <typename Result, typename Strategy>
- static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
- Result & result,
- Strategy const& strategy)
- {
- using gc1_view_t = random_access_view<Geometry1 const>;
- using gc2_view_t = random_access_view<Geometry2 const>;
- gc1_view_t const gc1_view(geometry1);
- gc2_view_t const gc2_view(geometry2);
- bool inters_found[2][3] = {{false, false, false}, {false, false, false}};
- bool disjoint_found[2][3] = {{false, false, false}, {false, false, false}};
- bool disjoint_linear_boundary_found[2] = {false, false};
- bool has_disjoint = false;
- gc_group_elements(gc1_view, gc2_view, strategy,
- [&](auto const& inters_group)
- {
- tuple1_t tuple1;
- tuple2_t tuple2;
-
-
- for (auto const& id : inters_group)
- {
- BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1);
- if (id.source_id == 0)
- {
- traits::iter_visit<gc1_view_t>::apply([&](auto const& g1)
- {
- merge_geometry(tuple1, g1, strategy);
- }, boost::begin(gc1_view) + id.gc_id);
- }
- else
- {
- traits::iter_visit<gc2_view_t>::apply([&](auto const& g2)
- {
- merge_geometry(tuple2, g2, strategy);
- }, boost::begin(gc2_view) + id.gc_id);
- }
- }
-
-
- subtract_elements(tuple1, strategy);
- subtract_elements(tuple2, strategy);
-
- auto const& mpt1 = boost::get<0>(tuple1);
- auto const& mls1 = boost::get<1>(tuple1);
- auto const& mpo1 = boost::get<2>(tuple1);
- auto const& mpt2 = boost::get<0>(tuple2);
- auto const& mls2 = boost::get<1>(tuple2);
- auto const& mpo2 = boost::get<2>(tuple2);
-
- if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpo2))
- {
- inters_found[0][2] = true;
- inters_found[1][2] = true;
- aa_handler_wrapper<Result> wrapper(result);
- call_relate(mpo1, mpo2, wrapper, strategy);
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
- bool is_aa_ii = result.template get<interior, interior>() != 'F';
- bool is_aa_ie = result.template get<interior, exterior>() != 'F';
- bool is_aa_ei = result.template get<exterior, interior>() != 'F';
-
- bool are_aa_equal = is_aa_ii && ! is_aa_ie && ! is_aa_ei;
-
- boundary_checker<mls1_t, Strategy> mls1_boundary(mls1, strategy);
- boundary_checker<mls2_t, Strategy> mls2_boundary(mls2, strategy);
-
-
-
- mls2_t mls2_diff_mpo1, mls2_inters_mpo1;
- bool is_mls2_divided = false;
- mls1_t mls1_diff_mpo2, mls1_inters_mpo2;
- bool is_mls1_divided = false;
-
- if (! are_aa_equal && ! geometry::is_empty(mls1) && ! geometry::is_empty(mls2))
- {
-
- if (! geometry::is_empty(mpo1))
- {
- geometry::difference(mls2, mpo1, mls2_diff_mpo1);
- geometry::intersection(mls2, mpo1, mls2_inters_mpo1);
- is_mls2_divided = true;
- }
-
- if (! geometry::is_empty(mpo2))
- {
- geometry::difference(mls1, mpo2, mls1_diff_mpo2);
- geometry::intersection(mls1, mpo2, mls1_inters_mpo2);
- is_mls1_divided = true;
- }
- }
-
- if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mls2))
- {
- inters_found[0][2] = true;
- inters_found[1][1] = true;
- if (is_aa_ii && ! is_aa_ie && ! is_aa_ei && ! geometry::is_empty(mls1))
- {
-
- }
- else if (is_aa_ii && ! is_aa_ie && geometry::is_empty(mls1))
- {
-
- mpo1_t empty;
- call_relate_al(empty, mls2, mls2_boundary, result, strategy);
- }
- else
- {
- if (is_mls2_divided)
- {
- if (! geometry::is_empty(mls2_inters_mpo1))
- {
- call_relate_al(mpo1, mls2_inters_mpo1, mls2_boundary, result, strategy);
- }
- }
- else
- {
- call_relate_al(mpo1, mls2, mls2_boundary, result, strategy);
- }
- }
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpo2))
- {
- inters_found[0][1] = true;
- inters_found[1][2] = true;
- if (is_aa_ii && ! is_aa_ei && ! is_aa_ie && ! geometry::is_empty(mls2))
- {
-
- }
- else if (is_aa_ii && ! is_aa_ei && geometry::is_empty(mls2))
- {
-
- mpo2_t empty;
- call_relate_la(mls1, empty, mls1_boundary, result, strategy);
- }
- else
- {
- if (is_mls1_divided)
- {
- if (! geometry::is_empty(mls1_inters_mpo2))
- {
- call_relate_la(mls1_inters_mpo2, mpo2, mls1_boundary, result, strategy);
- }
- }
- else
- {
- call_relate_la(mls1, mpo2, mls1_boundary, result, strategy);
- }
- }
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mls1) && ! geometry::is_empty(mls2))
- {
- inters_found[0][1] = true;
- inters_found[1][1] = true;
- if (is_mls1_divided && is_mls2_divided)
- {
- if (! geometry::is_empty(mls1_diff_mpo2) && ! geometry::is_empty(mls2_diff_mpo1))
- {
- call_relate_ll(mls1_diff_mpo2, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy);
- }
- }
- else if (is_mls1_divided)
- {
- if (! geometry::is_empty(mls1_diff_mpo2))
- {
- call_relate_ll(mls1_diff_mpo2, mls2, mls1_boundary, mls2_boundary, result, strategy);
- }
- }
- else if (is_mls2_divided)
- {
- if (! geometry::is_empty(mls2_diff_mpo1))
- {
- call_relate_ll(mls1, mls2_diff_mpo1, mls1_boundary, mls2_boundary, result, strategy);
- }
- }
- else
- {
- call_relate_ll(mls1, mls2, mls1_boundary, mls2_boundary, result, strategy);
- }
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mpo1) && ! geometry::is_empty(mpt2))
- {
- inters_found[0][2] = true;
- inters_found[1][0] = true;
- call_relate(mpo1, mpt2, result, strategy);
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpo2))
- {
- inters_found[0][0] = true;
- inters_found[1][2] = true;
- call_relate(mpt1, mpo2, result, strategy);
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mls1) && ! geometry::is_empty(mpt2))
- {
- inters_found[0][1] = true;
- inters_found[1][0] = true;
- call_relate(mls1, mpt2, result, strategy);
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mls2))
- {
- inters_found[0][0] = true;
- inters_found[1][1] = true;
- call_relate(mpt1, mls2, result, strategy);
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
-
- if (! geometry::is_empty(mpt1) && ! geometry::is_empty(mpt2))
- {
- inters_found[0][0] = true;
- inters_found[1][0] = true;
- call_relate(mpt1, mpt2, result, strategy);
- }
- if (BOOST_GEOMETRY_CONDITION(result.interrupt))
- {
- return false;
- }
- return true;
- },
- [&](auto const& disjoint_group)
- {
- for (auto const& id : disjoint_group)
- {
- BOOST_GEOMETRY_ASSERT(id.source_id == 0 || id.source_id == 1);
- if (id.source_id == 0)
- {
- traits::iter_visit<gc1_view_t>::apply([&](auto const& g1)
- {
- if (! geometry::is_empty(g1))
- {
- static const std::size_t index = kind_id<util::remove_cref_t<decltype(g1)>>::value;
- disjoint_found[0][index] = true;
- disjoint_linear_boundary_found[0] = has_linear_boundary(g1, strategy);
- has_disjoint = true;
- }
- }, boost::begin(gc1_view) + id.gc_id);
- }
- else
- {
- traits::iter_visit<gc2_view_t>::apply([&](auto const& g2)
- {
- if (! geometry::is_empty(g2))
- {
- static const std::size_t index = kind_id<util::remove_cref_t<decltype(g2)>>::value;
- disjoint_found[1][index] = true;
- disjoint_linear_boundary_found[1] = has_linear_boundary(g2, strategy);
- has_disjoint = true;
- }
- }, boost::begin(gc2_view) + id.gc_id);
- }
- }
- }, true);
-
- if (has_disjoint)
- {
- if (disjoint_found[0][2] == true)
- {
- update<interior, exterior, '2'>(result);
- update<boundary, exterior, '1'>(result);
- }
- else if (disjoint_found[0][1] == true)
- {
- update<interior, exterior, '1'>(result);
- if (disjoint_linear_boundary_found[0])
- {
- update<boundary, exterior, '0'>(result);
- }
- }
- else if (disjoint_found[0][0] == true)
- {
- update<interior, exterior, '0'>(result);
- }
- if (disjoint_found[1][2] == true)
- {
- update<exterior, interior, '2'>(result);
- update<exterior, boundary, '1'>(result);
- }
- else if (disjoint_found[1][1] == true)
- {
- update<exterior, interior, '1'>(result);
- if (disjoint_linear_boundary_found[1])
- {
- update<exterior, boundary, '0'>(result);
- }
- }
- else if (disjoint_found[1][0] == true)
- {
- update<exterior, interior, '0'>(result);
- }
- }
- }
- private:
- template <typename Tuple, typename Geometry, typename Strategy>
- static inline void merge_geometry(Tuple& tuple, Geometry const& geometry, Strategy const& strategy)
- {
- static const std::size_t index = kind_id<Geometry>::value;
- typename boost::tuples::element<index, Tuple>::type temp_out;
- geometry::union_(boost::get<index>(tuple), geometry, temp_out, strategy);
- boost::get<index>(tuple) = std::move(temp_out);
- }
- template <typename Tuple, typename Strategy>
- static inline void subtract_elements(Tuple& tuple, Strategy const& strategy)
- {
- if (! geometry::is_empty(boost::get<1>(tuple)))
- {
- if (! geometry::is_empty(boost::get<2>(tuple)))
- {
- typename boost::tuples::element<1, Tuple>::type mls;
- geometry::difference(boost::get<1>(tuple), boost::get<2>(tuple), mls, strategy);
- boost::get<1>(tuple) = std::move(mls);
- }
- }
- if (! geometry::is_empty(boost::get<0>(tuple)))
- {
- if (! geometry::is_empty(boost::get<2>(tuple)))
- {
- typename boost::tuples::element<0, Tuple>::type mpt;
- geometry::difference(boost::get<0>(tuple), boost::get<2>(tuple), mpt, strategy);
- boost::get<0>(tuple) = std::move(mpt);
- }
- if (! geometry::is_empty(boost::get<1>(tuple)))
- {
- typename boost::tuples::element<0, Tuple>::type mpt;
- geometry::difference(boost::get<0>(tuple), boost::get<1>(tuple), mpt, strategy);
- boost::get<0>(tuple) = std::move(mpt);
- }
- }
- }
- template
- <
- typename Geometry, typename Strategy,
- std::enable_if_t<util::is_linear<Geometry>::value, int> = 0
- >
- static inline bool has_linear_boundary(Geometry const& geometry, Strategy const& strategy)
- {
- topology_check<Geometry, Strategy> tc(geometry, strategy);
- return tc.has_boundary();
- }
- template
- <
- typename Geometry, typename Strategy,
- std::enable_if_t<! util::is_linear<Geometry>::value, int> = 0
- >
- static inline bool has_linear_boundary(Geometry const& , Strategy const& )
- {
- return false;
- }
- template <typename Multi1, typename Multi2, typename Result, typename Strategy>
- static inline void call_relate(Multi1 const& multi1, Multi2 const& multi2,
- Result& result, Strategy const& strategy)
- {
- dispatch::relate
- <
- Multi1, Multi2
- >::apply(multi1, multi2, result, strategy);
- }
- template <typename MLs, typename MPo, typename MLsBoundary, typename Result, typename Strategy>
- static inline void call_relate_la(MLs const& mls, MPo const& mpo,
- MLsBoundary const& mls_boundary,
- Result& result, Strategy const& strategy)
- {
- linear_areal<MLs, MPo>::apply(mls, mpo, mls_boundary, result, strategy);
- }
- template <typename MPo, typename MLs, typename MLsBoundary, typename Result, typename Strategy>
- static inline void call_relate_al(MPo const& mls, MLs const& mpo,
- MLsBoundary const& mls_boundary,
- Result& result, Strategy const& strategy)
- {
- areal_linear<MPo, MLs>::apply(mls, mpo, mls_boundary, result, strategy);
- }
- template <typename MLs1, typename MLs2, typename MLs1Boundary, typename MLs2Boundary, typename Result, typename Strategy>
- static inline void call_relate_ll(MLs1 const& mls1, MLs2 const& mls2,
- MLs1Boundary const& mls1_boundary,
- MLs2Boundary const& mls2_boundary,
- Result& result, Strategy const& strategy)
- {
- linear_linear<MLs1, MLs2>::apply(mls1, mls2, mls1_boundary, mls2_boundary,
- result, strategy);
- }
- };
- }}
- #endif
- #ifndef DOXYGEN_NO_DISPATCH
- namespace dispatch {
- template <typename Geometry1, typename Geometry2>
- struct relate<Geometry1, Geometry2, geometry_collection_tag, geometry_collection_tag, -1, -1, false>
- : detail::relate::gc_gc<Geometry1, Geometry2>
- {};
- template <typename Geometry1, typename Geometry2, typename Tag1, int TopDim1>
- struct relate<Geometry1, Geometry2, Tag1, geometry_collection_tag, TopDim1, -1, false>
- {
- static const bool interruption_enabled = true;
- template <typename Result, typename Strategy>
- static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
- Result & result,
- Strategy const& strategy)
- {
- using gc1_view_t = detail::geometry_collection_view<Geometry1>;
- relate<gc1_view_t, Geometry2>::apply(gc1_view_t(geometry1), geometry2, result, strategy);
- }
- };
- template <typename Geometry1, typename Geometry2, typename Tag2, int TopDim2>
- struct relate<Geometry1, Geometry2, geometry_collection_tag, Tag2, -1, TopDim2, false>
- {
- static const bool interruption_enabled = true;
- template <typename Result, typename Strategy>
- static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
- Result & result,
- Strategy const& strategy)
- {
- using gc2_view_t = detail::geometry_collection_view<Geometry2>;
- relate<Geometry1, gc2_view_t>::apply(geometry1, gc2_view_t(geometry2), result, strategy);
- }
- };
- }
- #endif
- }}
- #endif
|