File indexing completed on 2025-09-18 08:43:01
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DIFFERENCE_HPP
0016
0017
0018 #include <boost/geometry/algorithms/detail/gc_make_rtree.hpp>
0019 #include <boost/geometry/algorithms/detail/intersection/gc.hpp>
0020 #include <boost/geometry/algorithms/detail/intersection/multi.hpp>
0021 #include <boost/geometry/algorithms/detail/overlay/intersection_insert.hpp>
0022 #include <boost/geometry/algorithms/detail/visit.hpp>
0023 #include <boost/geometry/core/geometry_types.hpp>
0024 #include <boost/geometry/core/primary_single_tag.hpp>
0025 #include <boost/geometry/core/tag_cast.hpp>
0026 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
0027 #include <boost/geometry/strategies/default_strategy.hpp>
0028 #include <boost/geometry/strategies/detail.hpp>
0029 #include <boost/geometry/strategies/relate/cartesian.hpp>
0030 #include <boost/geometry/strategies/relate/geographic.hpp>
0031 #include <boost/geometry/strategies/relate/spherical.hpp>
0032 #include <boost/geometry/util/sequence.hpp>
0033 #include <boost/geometry/views/detail/geometry_collection_view.hpp>
0034
0035
0036 namespace boost { namespace geometry
0037 {
0038
0039 #ifndef DOXYGEN_NO_DETAIL
0040 namespace detail { namespace difference
0041 {
0042
0043
0044
0045 template <typename Geometry1, typename Geometry2>
0046 using is_subtractable_t = util::bool_constant
0047 <
0048 (geometry::topological_dimension<Geometry1>::value
0049 <= geometry::topological_dimension<Geometry2>::value)
0050 >;
0051
0052
0053 template
0054 <
0055 typename Geometry1,
0056 typename Geometry2,
0057 typename SingleOut,
0058 typename OutTag = typename detail::setop_insert_output_tag<SingleOut>::type,
0059 bool ReturnGeometry1 = (! is_subtractable_t<Geometry1, Geometry2>::value)
0060 >
0061 struct call_intersection_insert
0062 {
0063 template
0064 <
0065 typename OutputIterator,
0066 typename Strategy
0067 >
0068 static inline OutputIterator apply(Geometry1 const& geometry1,
0069 Geometry2 const& geometry2,
0070 OutputIterator out,
0071 Strategy const& strategy)
0072 {
0073 return geometry::dispatch::intersection_insert
0074 <
0075 Geometry1, Geometry2,
0076 SingleOut,
0077 overlay_difference,
0078 geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
0079 geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, true>::value
0080 >::apply(geometry1, geometry2, out, strategy);
0081 }
0082 };
0083
0084
0085 template <typename Geometry1, typename Geometry2, typename SingleOut, typename OutTag>
0086 struct call_intersection_insert<Geometry1, Geometry2, SingleOut, OutTag, true>
0087 {
0088 template <typename OutputIterator, typename Strategy>
0089 static inline OutputIterator apply(Geometry1 const& geometry1,
0090 Geometry2 const& ,
0091 OutputIterator out,
0092 Strategy const& )
0093 {
0094 return geometry::detail::convert_to_output
0095 <
0096 Geometry1,
0097 SingleOut
0098 >::apply(geometry1, out);
0099 }
0100 };
0101
0102
0103 template
0104 <
0105 typename Geometry1,
0106 typename Geometry2,
0107 typename SingleOut
0108 >
0109 struct call_intersection_insert_tupled_base
0110 {
0111 using single_tag = primary_single_tag_t
0112 <
0113 tag_cast_t<tag_t<Geometry1>, pointlike_tag, linear_tag, areal_tag>
0114 >;
0115
0116 typedef detail::expect_output
0117 <
0118 Geometry1, Geometry2, SingleOut, single_tag
0119 > expect_check;
0120
0121 typedef typename geometry::detail::output_geometry_access
0122 <
0123 SingleOut, single_tag, single_tag
0124 > access;
0125 };
0126
0127 template
0128 <
0129 typename Geometry1,
0130 typename Geometry2,
0131 typename SingleOut
0132 >
0133 struct call_intersection_insert
0134 <
0135 Geometry1, Geometry2, SingleOut,
0136 detail::tupled_output_tag,
0137 false
0138 >
0139 : call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut>
0140 {
0141 typedef call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut> base_t;
0142
0143 template
0144 <
0145 typename OutputIterator,
0146 typename Strategy
0147 >
0148 static inline OutputIterator apply(Geometry1 const& geometry1,
0149 Geometry2 const& geometry2,
0150 OutputIterator out,
0151 Strategy const& strategy)
0152 {
0153 base_t::access::get(out) = call_intersection_insert
0154 <
0155 Geometry1, Geometry2,
0156 typename base_t::access::type
0157 >::apply(geometry1, geometry2,
0158 base_t::access::get(out), strategy);
0159
0160 return out;
0161 }
0162 };
0163
0164 template
0165 <
0166 typename Geometry1,
0167 typename Geometry2,
0168 typename SingleOut
0169 >
0170 struct call_intersection_insert
0171 <
0172 Geometry1, Geometry2, SingleOut,
0173 detail::tupled_output_tag,
0174 true
0175 >
0176 : call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut>
0177 {
0178 typedef call_intersection_insert_tupled_base<Geometry1, Geometry2, SingleOut> base_t;
0179
0180 template
0181 <
0182 typename OutputIterator,
0183 typename Strategy
0184 >
0185 static inline OutputIterator apply(Geometry1 const& geometry1,
0186 Geometry2 const& ,
0187 OutputIterator out,
0188 Strategy const& )
0189 {
0190 base_t::access::get(out) = geometry::detail::convert_to_output
0191 <
0192 Geometry1,
0193 typename base_t::access::type
0194 >::apply(geometry1, base_t::access::get(out));
0195
0196 return out;
0197 }
0198 };
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 template
0220 <
0221 typename GeometryOut,
0222 typename Geometry1,
0223 typename Geometry2,
0224 typename OutputIterator,
0225 typename Strategy
0226 >
0227 inline OutputIterator difference_insert(Geometry1 const& geometry1,
0228 Geometry2 const& geometry2,
0229 OutputIterator out,
0230 Strategy const& strategy)
0231 {
0232 concepts::check<Geometry1 const>();
0233 concepts::check<Geometry2 const>();
0234
0235 geometry::detail::output_geometry_concept_check<GeometryOut>::apply();
0236
0237 return geometry::detail::difference::call_intersection_insert
0238 <
0239 Geometry1, Geometry2, GeometryOut
0240 >::apply(geometry1, geometry2, out, strategy);
0241 }
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259 template
0260 <
0261 typename GeometryOut,
0262 typename Geometry1,
0263 typename Geometry2,
0264 typename OutputIterator
0265 >
0266 inline OutputIterator difference_insert(Geometry1 const& geometry1,
0267 Geometry2 const& geometry2,
0268 OutputIterator out)
0269 {
0270 typedef typename strategies::relate::services::default_strategy
0271 <
0272 Geometry1,
0273 Geometry2
0274 >::type strategy_type;
0275
0276 return difference_insert<GeometryOut>(geometry1, geometry2, out,
0277 strategy_type());
0278 }
0279
0280
0281 template
0282 <
0283 typename Geometry, typename Collection,
0284 typename CastedTag = tag_cast_t<tag_t<Geometry>, pointlike_tag, linear_tag, areal_tag>
0285 >
0286 struct multi_output_type
0287 {
0288 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
0289 "Not implemented this Geometry type.",
0290 Geometry, CastedTag);
0291 };
0292
0293 template <typename Geometry, typename Collection>
0294 struct multi_output_type<Geometry, Collection, pointlike_tag>
0295 {
0296 using type = typename util::sequence_find_if
0297 <
0298 typename traits::geometry_types<Collection>::type,
0299 util::is_multi_point
0300 >::type;
0301 };
0302
0303 template <typename Geometry, typename Collection>
0304 struct multi_output_type<Geometry, Collection, linear_tag>
0305 {
0306 using type = typename util::sequence_find_if
0307 <
0308 typename traits::geometry_types<Collection>::type,
0309 util::is_multi_linestring
0310 >::type;
0311 };
0312
0313 template <typename Geometry, typename Collection>
0314 struct multi_output_type<Geometry, Collection, areal_tag>
0315 {
0316 using type = typename util::sequence_find_if
0317 <
0318 typename traits::geometry_types<Collection>::type,
0319 util::is_multi_polygon
0320 >::type;
0321 };
0322
0323
0324 }}
0325 #endif
0326
0327
0328 namespace resolve_collection
0329 {
0330
0331
0332 template
0333 <
0334 typename Geometry1, typename Geometry2, typename Collection,
0335 typename Tag1 = geometry::tag_t<Geometry1>,
0336 typename Tag2 = geometry::tag_t<Geometry2>,
0337 typename CollectionTag = geometry::tag_t<Collection>
0338 >
0339 struct difference
0340 {
0341 template <typename Strategy>
0342 static void apply(Geometry1 const& geometry1,
0343 Geometry2 const& geometry2,
0344 Collection & output_collection,
0345 Strategy const& strategy)
0346 {
0347 using single_out = typename geometry::detail::output_geometry_value
0348 <
0349 Collection
0350 >::type;
0351
0352 detail::difference::difference_insert<single_out>(
0353 geometry1, geometry2,
0354 geometry::detail::output_geometry_back_inserter(output_collection),
0355 strategy);
0356 }
0357 };
0358
0359 template <typename Geometry1, typename Geometry2, typename Collection>
0360 struct difference
0361 <
0362 Geometry1, Geometry2, Collection,
0363 geometry_collection_tag, geometry_collection_tag, geometry_collection_tag
0364 >
0365 {
0366 template <typename Strategy>
0367 static void apply(Geometry1 const& geometry1,
0368 Geometry2 const& geometry2,
0369 Collection& output_collection,
0370 Strategy const& strategy)
0371 {
0372 auto const rtree2 = detail::gc_make_rtree_iterators(geometry2, strategy);
0373 detail::visit_breadth_first([&](auto const& g1)
0374 {
0375
0376 typename detail::difference::multi_output_type
0377 <
0378 util::remove_cref_t<decltype(g1)>, Collection
0379 >::type out;
0380
0381 g1_minus_gc2(g1, rtree2, out, strategy);
0382
0383 detail::intersection::gc_move_multi_back(output_collection, out);
0384
0385 return true;
0386 }, geometry1);
0387 }
0388
0389 private:
0390
0391 template <typename G1, typename Rtree2, typename MultiOut, typename Strategy>
0392 static void g1_minus_gc2(G1 const& g1, Rtree2 const& rtree2, MultiOut& out, Strategy const& strategy)
0393 {
0394 {
0395 using single_out_t = typename geometry::detail::output_geometry_value<MultiOut>::type;
0396 auto out_it = geometry::detail::output_geometry_back_inserter(out);
0397 geometry::detail::convert_to_output<G1, single_out_t>::apply(g1, out_it);
0398 }
0399
0400 using box1_t = detail::gc_make_rtree_box_t<G1>;
0401 box1_t b1 = geometry::return_envelope<box1_t>(g1, strategy);
0402 detail::expand_by_epsilon(b1);
0403
0404 for (auto qit = rtree2.qbegin(index::intersects(b1)); qit != rtree2.qend(); ++qit)
0405 {
0406 traits::iter_visit<Geometry2>::apply([&](auto const& g2)
0407 {
0408 multi_out_minus_g2(out, g2, strategy);
0409 }, qit->second);
0410
0411 if (boost::empty(out))
0412 {
0413 return;
0414 }
0415 }
0416 }
0417
0418 template
0419 <
0420 typename MultiOut, typename G2, typename Strategy,
0421 std::enable_if_t<detail::difference::is_subtractable_t<MultiOut, G2>::value, int> = 0
0422 >
0423 static void multi_out_minus_g2(MultiOut& out, G2 const& g2, Strategy const& strategy)
0424 {
0425 MultiOut result;
0426 difference<MultiOut, G2, MultiOut>::apply(out, g2, result, strategy);
0427 out = std::move(result);
0428 }
0429
0430 template
0431 <
0432 typename MultiOut, typename G2, typename Strategy,
0433 std::enable_if_t<(! detail::difference::is_subtractable_t<MultiOut, G2>::value), int> = 0
0434 >
0435 static void multi_out_minus_g2(MultiOut& , G2 const& , Strategy const& )
0436 {}
0437 };
0438
0439
0440 template <typename Geometry1, typename Geometry2, typename Collection, typename Tag1>
0441 struct difference
0442 <
0443 Geometry1, Geometry2, Collection,
0444 Tag1, geometry_collection_tag, geometry_collection_tag
0445 >
0446 {
0447 template <typename Strategy>
0448 static void apply(Geometry1 const& geometry1,
0449 Geometry2 const& geometry2,
0450 Collection & output_collection,
0451 Strategy const& strategy)
0452 {
0453 using gc_view_t = geometry::detail::geometry_collection_view<Geometry1>;
0454 difference
0455 <
0456 gc_view_t, Geometry2, Collection
0457 >::apply(gc_view_t(geometry1), geometry2, output_collection, strategy);
0458 }
0459 };
0460
0461 template <typename Geometry1, typename Geometry2, typename Collection, typename Tag2>
0462 struct difference
0463 <
0464 Geometry1, Geometry2, Collection,
0465 geometry_collection_tag, Tag2, geometry_collection_tag
0466 >
0467 {
0468 template <typename Strategy>
0469 static void apply(Geometry1 const& geometry1,
0470 Geometry2 const& geometry2,
0471 Collection & output_collection,
0472 Strategy const& strategy)
0473 {
0474 using gc_view_t = geometry::detail::geometry_collection_view<Geometry2>;
0475 difference
0476 <
0477 Geometry1, gc_view_t, Collection
0478 >::apply(geometry1, gc_view_t(geometry2), output_collection, strategy);
0479 }
0480 };
0481
0482 template <typename Geometry1, typename Geometry2, typename Collection, typename Tag1, typename Tag2>
0483 struct difference
0484 <
0485 Geometry1, Geometry2, Collection,
0486 Tag1, Tag2, geometry_collection_tag
0487 >
0488 {
0489 template <typename Strategy>
0490 static void apply(Geometry1 const& geometry1,
0491 Geometry2 const& geometry2,
0492 Collection & output_collection,
0493 Strategy const& strategy)
0494 {
0495 using gc1_view_t = geometry::detail::geometry_collection_view<Geometry1>;
0496 using gc2_view_t = geometry::detail::geometry_collection_view<Geometry2>;
0497 difference
0498 <
0499 gc1_view_t, gc2_view_t, Collection
0500 >::apply(gc1_view_t(geometry1), gc2_view_t(geometry2), output_collection, strategy);
0501 }
0502 };
0503
0504
0505 }
0506
0507
0508 namespace resolve_strategy {
0509
0510 template
0511 <
0512 typename Strategy,
0513 bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategy>::value
0514 >
0515 struct difference
0516 {
0517 template <typename Geometry1, typename Geometry2, typename Collection>
0518 static inline void apply(Geometry1 const& geometry1,
0519 Geometry2 const& geometry2,
0520 Collection & output_collection,
0521 Strategy const& strategy)
0522 {
0523 resolve_collection::difference
0524 <
0525 Geometry1, Geometry2, Collection
0526 >::apply(geometry1, geometry2, output_collection, strategy);
0527 }
0528 };
0529
0530 template <typename Strategy>
0531 struct difference<Strategy, false>
0532 {
0533 template <typename Geometry1, typename Geometry2, typename Collection>
0534 static inline void apply(Geometry1 const& geometry1,
0535 Geometry2 const& geometry2,
0536 Collection & output_collection,
0537 Strategy const& strategy)
0538 {
0539 using strategies::relate::services::strategy_converter;
0540
0541 difference
0542 <
0543 decltype(strategy_converter<Strategy>::get(strategy))
0544 >::apply(geometry1, geometry2, output_collection,
0545 strategy_converter<Strategy>::get(strategy));
0546 }
0547 };
0548
0549 template <>
0550 struct difference<default_strategy, false>
0551 {
0552 template <typename Geometry1, typename Geometry2, typename Collection>
0553 static inline void apply(Geometry1 const& geometry1,
0554 Geometry2 const& geometry2,
0555 Collection & output_collection,
0556 default_strategy)
0557 {
0558 typedef typename strategies::relate::services::default_strategy
0559 <
0560 Geometry1,
0561 Geometry2
0562 >::type strategy_type;
0563
0564 difference
0565 <
0566 strategy_type
0567 >::apply(geometry1, geometry2, output_collection, strategy_type());
0568 }
0569 };
0570
0571 }
0572
0573
0574 namespace resolve_dynamic
0575 {
0576
0577 template
0578 <
0579 typename Geometry1, typename Geometry2,
0580 typename Tag1 = geometry::tag_t<Geometry1>,
0581 typename Tag2 = geometry::tag_t<Geometry2>
0582 >
0583 struct difference
0584 {
0585 template <typename Collection, typename Strategy>
0586 static void apply(Geometry1 const& geometry1, Geometry2 const& geometry2,
0587 Collection& output_collection, Strategy const& strategy)
0588 {
0589 resolve_strategy::difference
0590 <
0591 Strategy
0592 >::apply(geometry1, geometry2, output_collection, strategy);
0593 }
0594 };
0595
0596 template <typename DynamicGeometry1, typename Geometry2, typename Tag2>
0597 struct difference<DynamicGeometry1, Geometry2, dynamic_geometry_tag, Tag2>
0598 {
0599 template <typename Collection, typename Strategy>
0600 static void apply(DynamicGeometry1 const& geometry1, Geometry2 const& geometry2,
0601 Collection& output_collection, Strategy const& strategy)
0602 {
0603 traits::visit<DynamicGeometry1>::apply([&](auto const& g1)
0604 {
0605 resolve_strategy::difference
0606 <
0607 Strategy
0608 >::apply(g1, geometry2, output_collection, strategy);
0609 }, geometry1);
0610 }
0611 };
0612
0613 template <typename Geometry1, typename DynamicGeometry2, typename Tag1>
0614 struct difference<Geometry1, DynamicGeometry2, Tag1, dynamic_geometry_tag>
0615 {
0616 template <typename Collection, typename Strategy>
0617 static void apply(Geometry1 const& geometry1, DynamicGeometry2 const& geometry2,
0618 Collection& output_collection, Strategy const& strategy)
0619 {
0620 traits::visit<DynamicGeometry2>::apply([&](auto const& g2)
0621 {
0622 resolve_strategy::difference
0623 <
0624 Strategy
0625 >::apply(geometry1, g2, output_collection, strategy);
0626 }, geometry2);
0627 }
0628 };
0629
0630 template <typename DynamicGeometry1, typename DynamicGeometry2>
0631 struct difference<DynamicGeometry1, DynamicGeometry2, dynamic_geometry_tag, dynamic_geometry_tag>
0632 {
0633 template <typename Collection, typename Strategy>
0634 static void apply(DynamicGeometry1 const& geometry1, DynamicGeometry2 const& geometry2,
0635 Collection& output_collection, Strategy const& strategy)
0636 {
0637 traits::visit<DynamicGeometry1, DynamicGeometry2>::apply([&](auto const& g1, auto const& g2)
0638 {
0639 resolve_strategy::difference
0640 <
0641 Strategy
0642 >::apply(g1, g2, output_collection, strategy);
0643 }, geometry1, geometry2);
0644 }
0645 };
0646
0647 }
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666 template
0667 <
0668 typename Geometry1,
0669 typename Geometry2,
0670 typename Collection,
0671 typename Strategy
0672 >
0673 inline void difference(Geometry1 const& geometry1,
0674 Geometry2 const& geometry2,
0675 Collection& output_collection,
0676 Strategy const& strategy)
0677 {
0678 resolve_dynamic::difference
0679 <
0680 Geometry1,
0681 Geometry2
0682 >::apply(geometry1, geometry2, output_collection, strategy);
0683 }
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699 template
0700 <
0701 typename Geometry1,
0702 typename Geometry2,
0703 typename Collection
0704 >
0705 inline void difference(Geometry1 const& geometry1,
0706 Geometry2 const& geometry2,
0707 Collection& output_collection)
0708 {
0709 resolve_dynamic::difference
0710 <
0711 Geometry1,
0712 Geometry2
0713 >::apply(geometry1, geometry2, output_collection, default_strategy());
0714 }
0715
0716
0717 }}
0718
0719
0720 #endif