1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2015-2021.
6 // Modifications copyright (c) 2015-2021 Oracle and/or its affiliates.
8 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP
23 #include <boost/variant/apply_visitor.hpp>
24 #include <boost/variant/static_visitor.hpp>
25 #include <boost/variant/variant_fwd.hpp>
27 #include <boost/geometry/algorithms/intersection.hpp>
28 #include <boost/geometry/algorithms/union.hpp>
29 #include <boost/geometry/geometries/multi_polygon.hpp>
30 #include <boost/geometry/policies/robustness/get_rescale_policy.hpp>
31 #include <boost/geometry/strategies/default_strategy.hpp>
32 #include <boost/geometry/strategies/detail.hpp>
33 #include <boost/geometry/strategies/relate/cartesian.hpp>
34 #include <boost/geometry/strategies/relate/geographic.hpp>
35 #include <boost/geometry/strategies/relate/spherical.hpp>
36 #include <boost/geometry/util/range.hpp>
39 namespace boost { namespace geometry
42 #ifndef DOXYGEN_NO_DETAIL
43 namespace detail { namespace sym_difference
47 template <typename GeometryOut>
48 struct compute_difference
54 typename RobustPolicy,
55 typename OutputIterator,
58 static inline OutputIterator apply(Geometry1 const& geometry1,
59 Geometry2 const& geometry2,
60 RobustPolicy const& robust_policy,
62 Strategy const& strategy)
64 return geometry::dispatch::intersection_insert
70 geometry::detail::overlay::do_reverse
72 geometry::point_order<Geometry1>::value
74 geometry::detail::overlay::do_reverse
76 geometry::point_order<Geometry2>::value, true
78 >::apply(geometry1, geometry2, robust_policy, out, strategy);
84 template <typename GeometryOut, typename Geometry1, typename Geometry2>
85 struct sym_difference_generic
89 typename RobustPolicy,
90 typename OutputIterator,
93 static inline OutputIterator apply(Geometry1 const& geometry1,
94 Geometry2 const& geometry2,
95 RobustPolicy const& robust_policy,
97 Strategy const& strategy)
99 out = compute_difference
102 >::apply(geometry1, geometry2, robust_policy, out, strategy);
104 return compute_difference
107 >::apply(geometry2, geometry1, robust_policy, out, strategy);
112 template <typename GeometryOut, typename Areal1, typename Areal2>
113 struct sym_difference_areal_areal
117 typename RobustPolicy,
118 typename OutputIterator,
121 static inline OutputIterator apply(Areal1 const& areal1,
122 Areal2 const& areal2,
123 RobustPolicy const& robust_policy,
125 Strategy const& strategy)
127 typedef geometry::model::multi_polygon
130 > helper_geometry_type;
132 helper_geometry_type diff12, diff21;
134 std::back_insert_iterator<helper_geometry_type> oit12(diff12);
135 std::back_insert_iterator<helper_geometry_type> oit21(diff21);
140 >::apply(areal1, areal2, robust_policy, oit12, strategy);
145 >::apply(areal2, areal1, robust_policy, oit21, strategy);
147 return geometry::dispatch::union_insert
149 helper_geometry_type,
150 helper_geometry_type,
152 >::apply(diff12, diff21, robust_policy, out, strategy);
159 typename GeometryOut,
161 template <typename, typename, typename> class Algorithm
163 struct sym_difference_same_inputs_tupled_output
169 typename RobustPolicy,
170 typename OutputIterator,
173 static inline OutputIterator apply(Geometry1 const& geometry1,
174 Geometry2 const& geometry2,
175 RobustPolicy const& robust_policy,
177 Strategy const& strategy)
179 typedef typename geometry::detail::output_geometry_access
181 GeometryOut, SingleTag, SingleTag
184 access::get(out) = Algorithm
186 typename access::type, Geometry1, Geometry2
187 >::apply(geometry1, geometry2, robust_policy, access::get(out), strategy);
196 typename GeometryOut,
199 bool Reverse = (geometry::core_dispatch::top_dim<SingleTag1>::value
200 > geometry::core_dispatch::top_dim<SingleTag2>::value)
202 struct sym_difference_different_inputs_tupled_output
208 typename RobustPolicy,
209 typename OutputIterator,
212 static inline OutputIterator apply(Geometry1 const& geometry1,
213 Geometry2 const& geometry2,
214 RobustPolicy const& robust_policy,
216 Strategy const& strategy)
218 return sym_difference_different_inputs_tupled_output
220 GeometryOut, SingleTag2, SingleTag1
221 >::apply(geometry2, geometry1, robust_policy, out, strategy);
227 typename GeometryOut,
231 struct sym_difference_different_inputs_tupled_output
233 GeometryOut, SingleTag1, SingleTag2, false
240 typename RobustPolicy,
241 typename OutputIterator,
244 static inline OutputIterator apply(Geometry1 const& geometry1,
245 Geometry2 const& geometry2,
246 RobustPolicy const& robust_policy,
248 Strategy const& strategy)
250 typedef typename geometry::detail::output_geometry_access
252 GeometryOut, SingleTag1, SingleTag1
254 typedef typename geometry::detail::output_geometry_access
256 GeometryOut, SingleTag2, SingleTag2
259 access1::get(out) = compute_difference
261 typename access1::type
262 >::apply(geometry1, geometry2, robust_policy, access1::get(out), strategy);
264 access2::get(out) = geometry::detail::convert_to_output
267 typename access2::type
268 >::apply(geometry2, access2::get(out));
275 }} // namespace detail::sym_difference
276 #endif // DOXYGEN_NO_DETAIL
280 #ifndef DOXYGEN_NO_DISPATCH
289 typename GeometryOut,
290 typename TagIn1 = typename geometry::tag_cast
292 typename tag<Geometry1>::type, pointlike_tag, linear_tag, areal_tag
294 typename TagIn2 = typename geometry::tag_cast
296 typename tag<Geometry2>::type, pointlike_tag, linear_tag, areal_tag
298 typename TagOut = typename detail::setop_insert_output_tag<GeometryOut>::type
300 struct sym_difference_insert
301 : detail::sym_difference::sym_difference_generic
303 GeometryOut, Geometry1, Geometry2
312 typename GeometryOut,
315 struct sym_difference_insert
317 Areal1, Areal2, GeometryOut,
318 areal_tag, areal_tag, TagOut
319 > : detail::sym_difference::sym_difference_areal_areal
321 GeometryOut, Areal1, Areal2
333 struct sym_difference_insert
335 PointLike1, PointLike2, GeometryOut,
336 pointlike_tag, pointlike_tag, detail::tupled_output_tag
338 : detail::expect_output<PointLike1, PointLike2, GeometryOut, point_tag>
339 , detail::sym_difference::sym_difference_same_inputs_tupled_output
343 detail::sym_difference::sym_difference_generic
353 struct sym_difference_insert
355 Linear1, Linear2, GeometryOut,
356 linear_tag, linear_tag, detail::tupled_output_tag
358 : detail::expect_output<Linear1, Linear2, GeometryOut, linestring_tag>
359 , detail::sym_difference::sym_difference_same_inputs_tupled_output
363 detail::sym_difference::sym_difference_generic
373 struct sym_difference_insert
375 Areal1, Areal2, GeometryOut,
376 areal_tag, areal_tag, detail::tupled_output_tag
378 : detail::expect_output<Areal1, Areal2, GeometryOut, polygon_tag>
379 , detail::sym_difference::sym_difference_same_inputs_tupled_output
383 detail::sym_difference::sym_difference_areal_areal
391 typename GeometryOut,
395 struct sym_difference_insert
397 Geometry1, Geometry2, GeometryOut,
398 TagIn1, TagIn2, detail::tupled_output_tag
400 : detail::expect_output
402 Geometry1, Geometry2, GeometryOut,
403 typename detail::single_tag_from_base_tag<TagIn1>::type,
404 typename detail::single_tag_from_base_tag<TagIn2>::type
406 , detail::sym_difference::sym_difference_different_inputs_tupled_output
409 typename detail::single_tag_from_base_tag<TagIn1>::type,
410 typename detail::single_tag_from_base_tag<TagIn2>::type
415 } // namespace dispatch
416 #endif // DOXYGEN_NO_DISPATCH
420 #ifndef DOXYGEN_NO_DETAIL
421 namespace detail { namespace sym_difference
427 \brief \brief_calc2{symmetric difference} \brief_strategy
428 \ingroup sym_difference
429 \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}
430 \brief_strategy. \details_insert{sym_difference}
431 \tparam GeometryOut output geometry type, must be specified
432 \tparam Geometry1 \tparam_geometry
433 \tparam Geometry2 \tparam_geometry
434 \tparam Strategy \tparam_strategy_overlay
435 \param geometry1 \param_geometry
436 \param geometry2 \param_geometry
437 \param out \param_out{difference}
438 \param strategy \param_strategy{difference}
441 \qbk{distinguish,with strategy}
445 typename GeometryOut,
448 typename OutputIterator,
451 inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
452 Geometry2 const& geometry2,
454 Strategy const& strategy)
456 concepts::check<Geometry1 const>();
457 concepts::check<Geometry2 const>();
458 //concepts::check<GeometryOut>();
459 geometry::detail::output_geometry_concept_check<GeometryOut>::apply();
461 typedef typename geometry::rescale_overlay_policy_type
465 typename Strategy::cs_tag
466 >::type rescale_policy_type;
468 rescale_policy_type robust_policy
469 = geometry::get_rescale_policy<rescale_policy_type>(
470 geometry1, geometry2, strategy);
472 return dispatch::sym_difference_insert
474 Geometry1, Geometry2, GeometryOut
475 >::apply(geometry1, geometry2, robust_policy, out, strategy);
480 \brief \brief_calc2{symmetric difference}
481 \ingroup sym_difference
482 \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}
483 \details_insert{sym_difference}
484 \tparam GeometryOut output geometry type, must be specified
485 \tparam Geometry1 \tparam_geometry
486 \tparam Geometry2 \tparam_geometry
487 \param geometry1 \param_geometry
488 \param geometry2 \param_geometry
489 \param out \param_out{difference}
495 typename GeometryOut,
498 typename OutputIterator
500 inline OutputIterator sym_difference_insert(Geometry1 const& geometry1,
501 Geometry2 const& geometry2, OutputIterator out)
503 typedef typename strategies::relate::services::default_strategy
506 >::type strategy_type;
508 return sym_difference_insert<GeometryOut>(geometry1, geometry2, out, strategy_type());
511 }} // namespace detail::sym_difference
512 #endif // DOXYGEN_NO_DETAIL
515 namespace resolve_strategy {
520 bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
522 struct sym_difference
524 template <typename Geometry1, typename Geometry2, typename Collection>
525 static inline void apply(Geometry1 const& geometry1,
526 Geometry2 const& geometry2,
527 Collection & output_collection,
528 Strategy const& strategy)
530 typedef typename geometry::detail::output_geometry_value
535 detail::sym_difference::sym_difference_insert<single_out>(
536 geometry1, geometry2,
537 geometry::detail::output_geometry_back_inserter(output_collection),
542 template <typename Strategy>
543 struct sym_difference<Strategy, false>
545 template <typename Geometry1, typename Geometry2, typename Collection>
546 static inline void apply(Geometry1 const& geometry1,
547 Geometry2 const& geometry2,
548 Collection & output_collection,
549 Strategy const& strategy)
551 using strategies::relate::services::strategy_converter;
555 decltype(strategy_converter<Strategy>::get(strategy))
556 >::apply(geometry1, geometry2, output_collection,
557 strategy_converter<Strategy>::get(strategy));
562 struct sym_difference<default_strategy, false>
564 template <typename Geometry1, typename Geometry2, typename Collection>
565 static inline void apply(Geometry1 const& geometry1,
566 Geometry2 const& geometry2,
567 Collection & output_collection,
570 typedef typename strategies::relate::services::default_strategy
573 >::type strategy_type;
578 >::apply(geometry1, geometry2, output_collection, strategy_type());
582 } // resolve_strategy
585 namespace resolve_variant
588 template <typename Geometry1, typename Geometry2>
589 struct sym_difference
591 template <typename Collection, typename Strategy>
592 static inline void apply(Geometry1 const& geometry1,
593 Geometry2 const& geometry2,
594 Collection& output_collection,
595 Strategy const& strategy)
597 resolve_strategy::sym_difference
600 >::apply(geometry1, geometry2, output_collection, strategy);
605 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
606 struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
608 template <typename Collection, typename Strategy>
609 struct visitor: static_visitor<>
611 Geometry2 const& m_geometry2;
612 Collection& m_output_collection;
613 Strategy const& m_strategy;
615 visitor(Geometry2 const& geometry2,
616 Collection& output_collection,
617 Strategy const& strategy)
618 : m_geometry2(geometry2)
619 , m_output_collection(output_collection)
620 , m_strategy(strategy)
623 template <typename Geometry1>
624 void operator()(Geometry1 const& geometry1) const
630 >::apply(geometry1, m_geometry2, m_output_collection, m_strategy);
634 template <typename Collection, typename Strategy>
636 apply(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
637 Geometry2 const& geometry2,
638 Collection& output_collection,
639 Strategy const& strategy)
641 boost::apply_visitor(visitor<Collection, Strategy>(geometry2,
649 template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
650 struct sym_difference<Geometry1, variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
652 template <typename Collection, typename Strategy>
653 struct visitor: static_visitor<>
655 Geometry1 const& m_geometry1;
656 Collection& m_output_collection;
657 Strategy const& m_strategy;
659 visitor(Geometry1 const& geometry1,
660 Collection& output_collection,
661 Strategy const& strategy)
662 : m_geometry1(geometry1)
663 , m_output_collection(output_collection)
664 , m_strategy(strategy)
667 template <typename Geometry2>
668 void operator()(Geometry2 const& geometry2) const
674 >::apply(m_geometry1, geometry2, m_output_collection, m_strategy);
678 template <typename Collection, typename Strategy>
680 apply(Geometry1 const& geometry1,
681 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
682 Collection& output_collection,
683 Strategy const& strategy)
685 boost::apply_visitor(visitor<Collection, Strategy>(geometry1,
693 template <BOOST_VARIANT_ENUM_PARAMS(typename T1), BOOST_VARIANT_ENUM_PARAMS(typename T2)>
694 struct sym_difference<variant<BOOST_VARIANT_ENUM_PARAMS(T1)>, variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
696 template <typename Collection, typename Strategy>
697 struct visitor: static_visitor<>
699 Collection& m_output_collection;
700 Strategy const& m_strategy;
702 visitor(Collection& output_collection, Strategy const& strategy)
703 : m_output_collection(output_collection)
704 , m_strategy(strategy)
707 template <typename Geometry1, typename Geometry2>
708 void operator()(Geometry1 const& geometry1,
709 Geometry2 const& geometry2) const
715 >::apply(geometry1, geometry2, m_output_collection, m_strategy);
719 template <typename Collection, typename Strategy>
721 apply(variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
722 variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
723 Collection& output_collection,
724 Strategy const& strategy)
726 boost::apply_visitor(visitor<Collection, Strategy>(output_collection,
728 geometry1, geometry2);
732 } // namespace resolve_variant
736 \brief \brief_calc2{symmetric difference}
737 \ingroup sym_difference
738 \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}.
739 \tparam Geometry1 \tparam_geometry
740 \tparam Geometry2 \tparam_geometry
741 \tparam Collection output collection, either a multi-geometry,
742 or a std::vector<Geometry> / std::deque<Geometry> etc
743 \tparam Strategy \tparam_strategy{Sym_difference}
744 \param geometry1 \param_geometry
745 \param geometry2 \param_geometry
746 \param output_collection the output collection
747 \param strategy \param_strategy{sym_difference}
749 \qbk{distinguish,with strategy}
750 \qbk{[include reference/algorithms/sym_difference.qbk]}
759 inline void sym_difference(Geometry1 const& geometry1,
760 Geometry2 const& geometry2,
761 Collection& output_collection,
762 Strategy const& strategy)
764 resolve_variant::sym_difference
768 >::apply(geometry1, geometry2, output_collection, strategy);
773 \brief \brief_calc2{symmetric difference}
774 \ingroup sym_difference
775 \details \details_calc2{symmetric difference, spatial set theoretic symmetric difference (XOR)}.
776 \tparam Geometry1 \tparam_geometry
777 \tparam Geometry2 \tparam_geometry
778 \tparam Collection output collection, either a multi-geometry,
779 or a std::vector<Geometry> / std::deque<Geometry> etc
780 \param geometry1 \param_geometry
781 \param geometry2 \param_geometry
782 \param output_collection the output collection
784 \qbk{[include reference/algorithms/sym_difference.qbk]}
792 inline void sym_difference(Geometry1 const& geometry1,
793 Geometry2 const& geometry2,
794 Collection& output_collection)
796 resolve_variant::sym_difference
800 >::apply(geometry1, geometry2, output_collection, default_strategy());
804 }} // namespace boost::geometry
807 #endif // BOOST_GEOMETRY_ALGORITHMS_SYM_DIFFERENCE_HPP