|
| 1 | +// Copyright (c) 2025 Tel-Aviv University (Israel). |
| 2 | +// All rights reserved. |
| 3 | +// |
| 4 | +// This file is part of CGAL (www.cgal.org). |
| 5 | +// |
| 6 | +// $URL$ |
| 7 | +// $Id$ |
| 8 | +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial |
| 9 | +// |
| 10 | +// |
| 11 | +// Author(s): Efi Fogel <[email protected]> |
| 12 | + |
| 13 | +#ifndef CGAL_ARR_DO_INTERSECT_OVERLAY_2_H |
| 14 | +#define CGAL_ARR_DO_INTERSECT_OVERLAY_2_H |
| 15 | + |
| 16 | +#include <CGAL/license/Arrangement_on_surface_2.h> |
| 17 | + |
| 18 | +#include <CGAL/disable_warnings.h> |
| 19 | + |
| 20 | +/*! \file |
| 21 | + * |
| 22 | + * Definition of the global do_intersect_overlay_2() function. |
| 23 | + */ |
| 24 | + |
| 25 | +#include <CGAL/Arrangement_on_surface_2.h> |
| 26 | +#include <CGAL/Surface_sweep_2.h> |
| 27 | +#include <CGAL/Surface_sweep_2/Arr_default_overlay_traits_base.h> |
| 28 | +#include <CGAL/Surface_sweep_2/Arr_overlay_traits_2.h> |
| 29 | +#include <CGAL/Surface_sweep_2/Arr_do_intersect_overlay_ss_visitor.h> |
| 30 | +#include <CGAL/Surface_sweep_2/Arr_overlay_event.h> |
| 31 | +#include <CGAL/Surface_sweep_2/Arr_overlay_subcurve.h> |
| 32 | +#include <CGAL/assertions.h> |
| 33 | + |
| 34 | +namespace CGAL { |
| 35 | + |
| 36 | +/*! Compute the overlay of two input arrangements. |
| 37 | + * \tparam GeometryTraitsA_2 the geometry traits of the first arrangement. |
| 38 | + * \tparam GeometryTraitsB_2 the geometry traits of the second arrangement. |
| 39 | + * \tparam GeometryTraitsRes_2 the geometry traits of the resulting arrangement. |
| 40 | + * \tparam TopologyTraitsA the topology traits of the first arrangement. |
| 41 | + * \tparam TopologyTraitsB the topology traits of the second arrangement. |
| 42 | + * \tparam TopologyTraitsRes the topology traits of the resulting arrangement. |
| 43 | + * \tparam OverlayTraits An overlay-traits class. As arr1, arr2 and res can be |
| 44 | + * templated with different geometry-traits class and |
| 45 | + * different DCELs (encapsulated in the various topology-traits |
| 46 | + * classes). The geometry-traits of the result arrangement is |
| 47 | + * used to construct the result arrangement. This means that all |
| 48 | + * the types (e.g., Point_2, Curve_2 and X_monotone_2) of both |
| 49 | + * arr1 and arr2 have to be convertible to the types |
| 50 | + * in the result geometry-traits. |
| 51 | + * The overlay-traits class defines the various |
| 52 | + * overlay operations of pairs of DCEL features from |
| 53 | + * TopologyTraitsA and TopologyTraitsB to the resulting ResDcel. |
| 54 | + */ |
| 55 | +template <typename GeometryTraitsA_2, |
| 56 | + typename GeometryTraitsB_2, |
| 57 | + typename GeometryTraitsRes_2, |
| 58 | + typename TopologyTraitsA, |
| 59 | + typename TopologyTraitsB, |
| 60 | + typename TopologyTraitsRes, |
| 61 | + typename OverlayTraits> |
| 62 | +bool do_intersect_overlay(const Arrangement_on_surface_2<GeometryTraitsA_2, TopologyTraitsA>& arr1, |
| 63 | + const Arrangement_on_surface_2<GeometryTraitsB_2, TopologyTraitsB>& arr2, |
| 64 | + Arrangement_on_surface_2<GeometryTraitsRes_2, TopologyTraitsRes>& arr, |
| 65 | + OverlayTraits& ovl_tr, |
| 66 | + bool ignore_isolated_vertices = true) { |
| 67 | + using Agt2 = GeometryTraitsA_2; |
| 68 | + using Bgt2 = GeometryTraitsB_2; |
| 69 | + using Rgt2 = GeometryTraitsRes_2; |
| 70 | + using Att = TopologyTraitsA; |
| 71 | + using Btt = TopologyTraitsB; |
| 72 | + using Rtt = TopologyTraitsRes; |
| 73 | + using Overlay_traits = OverlayTraits; |
| 74 | + |
| 75 | + using Arr_a = Arrangement_on_surface_2<Agt2, Att>; |
| 76 | + using Arr_b = Arrangement_on_surface_2<Bgt2, Btt>; |
| 77 | + using Arr_res = Arrangement_on_surface_2<Rgt2, Rtt>; |
| 78 | + using Allocator = typename Arr_res::Allocator; |
| 79 | + |
| 80 | + // some type assertions (not all, but better than nothing). |
| 81 | + using A_point = typename Agt2::Point_2; |
| 82 | + using B_point = typename Bgt2::Point_2; |
| 83 | + using Res_point = typename Rgt2::Point_2; |
| 84 | + static_assert(std::is_convertible<A_point, Res_point>::value); |
| 85 | + static_assert(std::is_convertible<B_point, Res_point>::value); |
| 86 | + |
| 87 | + using A_xcv = typename Agt2::X_monotone_curve_2; |
| 88 | + using B_xcv = typename Bgt2::X_monotone_curve_2; |
| 89 | + using Res_xcv = typename Rgt2::X_monotone_curve_2; |
| 90 | + static_assert(std::is_convertible<A_xcv, Res_xcv>::value); |
| 91 | + static_assert(std::is_convertible<B_xcv, Res_xcv>::value); |
| 92 | + |
| 93 | + using Gt_adaptor_2 = Arr_traits_basic_adaptor_2<Rgt2>; |
| 94 | + using Ovl_gt2 = Arr_overlay_traits_2<Gt_adaptor_2, Arr_a, Arr_b>; |
| 95 | + using Ovl_event = Arr_overlay_event<Ovl_gt2, Arr_res, Allocator>; |
| 96 | + using Ovl_curve = Arr_overlay_subcurve<Ovl_gt2, Ovl_event, Allocator>; |
| 97 | + using Ovl_helper = typename TopologyTraitsRes::template Overlay_helper<Ovl_gt2, Ovl_event, Ovl_curve, Arr_a, Arr_b>; |
| 98 | + using Diovl_visitor = Arr_do_intersect_overlay_ss_visitor<Ovl_helper, Overlay_traits>; |
| 99 | + |
| 100 | + using Ovl_x_monotone_curve_2 = typename Ovl_gt2::X_monotone_curve_2; |
| 101 | + using Ovl_point_2 = typename Ovl_gt2::Point_2; |
| 102 | + using Cell_handle_red = typename Ovl_gt2::Cell_handle_red; |
| 103 | + using Optional_cell_red = typename Ovl_gt2::Optional_cell_red; |
| 104 | + using Cell_handle_blue = typename Ovl_gt2::Cell_handle_blue; |
| 105 | + using Optional_cell_blue = typename Ovl_gt2::Optional_cell_blue; |
| 106 | + |
| 107 | + CGAL_USE_TYPE(Optional_cell_red); |
| 108 | + CGAL_USE_TYPE(Optional_cell_blue); |
| 109 | + |
| 110 | + // The result arrangement cannot be on of the input arrangements. |
| 111 | + CGAL_precondition(((void*)(&arr) != (void*)(&arr1)) && ((void*)(&arr) != (void*)(&arr2))); |
| 112 | + |
| 113 | + // Prepare a vector of extended x-monotone curves that represent all edges |
| 114 | + // in both input arrangements. Each curve is associated with a halfedge |
| 115 | + // directed from right to left. |
| 116 | + typename Arr_a::Halfedge_const_handle invalid_he1; |
| 117 | + typename Arr_b::Halfedge_const_handle invalid_he2; |
| 118 | + std::vector<Ovl_x_monotone_curve_2> xcvs(arr1.number_of_edges() + arr2.number_of_edges()); |
| 119 | + std::size_t i = 0; |
| 120 | + |
| 121 | + for (auto eit1 = arr1.edges_begin(); eit1 != arr1.edges_end(); ++eit1, ++i) { |
| 122 | + typename Arr_a::Halfedge_const_handle he1 = eit1; |
| 123 | + if (he1->direction() != ARR_RIGHT_TO_LEFT) he1 = he1->twin(); |
| 124 | + xcvs[i] = Ovl_x_monotone_curve_2(eit1->curve(), he1, invalid_he2); |
| 125 | + } |
| 126 | + |
| 127 | + for (auto eit2 = arr2.edges_begin(); eit2 != arr2.edges_end(); ++eit2, ++i) { |
| 128 | + typename Arr_b::Halfedge_const_handle he2 = eit2; |
| 129 | + if (he2->direction() != ARR_RIGHT_TO_LEFT) he2 = he2->twin(); |
| 130 | + xcvs[i] = Ovl_x_monotone_curve_2(eit2->curve(), invalid_he1, he2); |
| 131 | + } |
| 132 | + |
| 133 | + // Obtain an extended traits-class object and define the sweep-line visitor. |
| 134 | + const typename Arr_res::Traits_adaptor_2* traits_adaptor = arr.traits_adaptor(); |
| 135 | + |
| 136 | + /* We would like to avoid copy construction of the geometry traits class. |
| 137 | + * Copy construction is undesired, because it may results with data |
| 138 | + * duplication or even data loss. |
| 139 | + * |
| 140 | + * If the type Ovl_gt2 is the same as the type |
| 141 | + * GeomTraits, use a reference to GeomTraits to avoid constructing a new one. |
| 142 | + * Otherwise, instantiate a local variable of the former and provide |
| 143 | + * the latter as a single parameter to the constructor. |
| 144 | + * |
| 145 | + * Use the form 'A a(*b);' and not ''A a = b;' to handle the case where A has |
| 146 | + * only an implicit constructor, (which takes *b as a parameter). |
| 147 | + */ |
| 148 | + std::conditional_t<std::is_same_v<Gt_adaptor_2, Ovl_gt2>, const Ovl_gt2&, Ovl_gt2> ex_traits(*traits_adaptor); |
| 149 | + |
| 150 | + Diovl_visitor visitor(&arr1, &arr2, &arr, &ovl_tr); |
| 151 | + Ss2::Surface_sweep_2<Diovl_visitor> surface_sweep(&ex_traits, &visitor); |
| 152 | + |
| 153 | + // In case both arrangement do not contain isolated vertices, go on and overlay them. |
| 154 | + if (ignore_isolated_vertices || |
| 155 | + ((arr1.number_of_isolated_vertices() == 0) && (arr2.number_of_isolated_vertices() == 0))) { |
| 156 | + // Clear the result arrangement and perform the sweep to construct it. |
| 157 | + arr.clear(); |
| 158 | + if (std::is_same<typename Agt2::Bottom_side_category, Arr_contracted_side_tag>::value) { |
| 159 | + surface_sweep.sweep(xcvs.begin(), xcvs.end()); |
| 160 | + xcvs.clear(); |
| 161 | + return visitor.found_intersection(); |
| 162 | + } |
| 163 | + surface_sweep.indexed_sweep(xcvs, Indexed_sweep_accessor<Arr_a, Arr_b, Ovl_x_monotone_curve_2>(arr1, arr2)); |
| 164 | + xcvs.clear(); |
| 165 | + return visitor.found_intersection(); |
| 166 | + } |
| 167 | + |
| 168 | + // Prepare a vector of extended points that represent all isolated vertices |
| 169 | + // in both input arrangements. |
| 170 | + std::vector<Ovl_point_2> pts_vec(arr1.number_of_isolated_vertices() + arr2.number_of_isolated_vertices()); |
| 171 | + |
| 172 | + i = 0; |
| 173 | + for (auto vit1 = arr1.vertices_begin(); vit1 != arr1.vertices_end(); ++vit1) { |
| 174 | + if (vit1->is_isolated()) { |
| 175 | + typename Arr_a::Vertex_const_handle v1 = vit1; |
| 176 | + pts_vec[i++] = Ovl_point_2(vit1->point(), std::make_optional(Cell_handle_red(v1)), |
| 177 | + std::optional<Cell_handle_blue>()); |
| 178 | + } |
| 179 | + } |
| 180 | + |
| 181 | + for (auto vit2 = arr2.vertices_begin(); vit2 != arr2.vertices_end(); ++vit2) { |
| 182 | + if (vit2->is_isolated()) { |
| 183 | + typename Arr_b::Vertex_const_handle v2 = vit2; |
| 184 | + pts_vec[i++] = Ovl_point_2(vit2->point(), std::optional<Cell_handle_red>(), |
| 185 | + std::make_optional(Cell_handle_blue(v2))); |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + // Clear the result arrangement and perform the sweep to construct it. |
| 190 | + arr.clear(); |
| 191 | + if (std::is_same<typename Agt2::Bottom_side_category, Arr_contracted_side_tag>::value) { |
| 192 | + surface_sweep.sweep(xcvs.begin(), xcvs.end(), pts_vec.begin(), pts_vec.end()); |
| 193 | + xcvs.clear(); |
| 194 | + pts_vec.clear(); |
| 195 | + return visitor.found_intersection(); |
| 196 | + } |
| 197 | + surface_sweep.indexed_sweep(xcvs, Indexed_sweep_accessor<Arr_a, Arr_b, Ovl_x_monotone_curve_2>(arr1, arr2), |
| 198 | + pts_vec.begin(), pts_vec.end()); |
| 199 | + xcvs.clear(); |
| 200 | + pts_vec.clear(); |
| 201 | + return visitor.found_intersection(); |
| 202 | +} |
| 203 | + |
| 204 | +/*! Compute the (simple) overlay of two input arrangements. |
| 205 | + * \param[in] arr1 the first arrangement. |
| 206 | + * \param[in] arr2 the second arrangement. |
| 207 | + * \param[out] arr the resulting arrangement. |
| 208 | + */ |
| 209 | +template <typename GeometryTraitsA_2, |
| 210 | + typename GeometryTraitsB_2, |
| 211 | + typename GeometryTraitsRes_2, |
| 212 | + typename TopologyTraitsA, |
| 213 | + typename TopologyTraitsB, |
| 214 | + typename TopologyTraitsRes> |
| 215 | +bool do_intersect_overlay(const Arrangement_on_surface_2<GeometryTraitsA_2, TopologyTraitsA>& arr1, |
| 216 | + const Arrangement_on_surface_2<GeometryTraitsB_2, TopologyTraitsB>& arr2, |
| 217 | + Arrangement_on_surface_2<GeometryTraitsRes_2, TopologyTraitsRes>& arr) { |
| 218 | + using Agt2 = GeometryTraitsA_2; |
| 219 | + using Bgt2 = GeometryTraitsB_2; |
| 220 | + using Rgt2 = GeometryTraitsRes_2; |
| 221 | + using Att = TopologyTraitsA; |
| 222 | + using Btt = TopologyTraitsB; |
| 223 | + using Rtt = TopologyTraitsRes; |
| 224 | + using Arr_a = Arrangement_on_surface_2<Agt2, Att>; |
| 225 | + using Arr_b = Arrangement_on_surface_2<Bgt2, Btt>; |
| 226 | + using Arr_res = Arrangement_on_surface_2<Rgt2, Rtt>; |
| 227 | + |
| 228 | + _Arr_default_overlay_traits_base<Arr_a, Arr_b, Arr_res> ovl_traits; |
| 229 | + return do_intersect_overlay(arr1, arr2, arr, ovl_traits); |
| 230 | +} |
| 231 | + |
| 232 | +} // namespace CGAL |
| 233 | + |
| 234 | +#include <CGAL/enable_warnings.h> |
| 235 | + |
| 236 | +#endif |
0 commit comments