Skip to content

Commit 1069678

Browse files
authored
Optimize the do_intersect() functions of the 2D Regularized Boolean Set Operation" package (made it tolerant to inexact kernels.) (#9050)
## Summary of Changes Optimized `do_intersect(polygon, polygon)`, `do_intersect(begin, end)`, and `do_intersect(begin1, end1, begin2, end2)`: (i) Terminated the execution once an intersection is detected. (In the past, the intersection was computed in one phase and examined in a subsequent phase.) (ii) Made the variants of the free functions `do_intersect()` that apply to linear polygons, robust even with an inexact-construction kernel. The variants that apply to generalized polygons endure inexact constructions much more than before; however, there are rare degenerate cases that are still require an exact construction kernel. In general, the changes described here do not affect the default interface, so a small feature is not required. However, it is a major impact, and it does affect the interface as described bellow, and even somehow break backward compatibility. Recently, the code of the package "2D Regularized Boolean Set Operations" was optimized. In particular, a 3rd optional parameter was introduced in the free functions. It determined whether the boundaries of the input polygons are treated as cyclic sequences of single (`x`-monotone) segments or as a cyclic sequences of (`x`-monotone) polylines. The change described here eliminates this 3rd parameter, and brings the interface of the `do_intersect() function back to the original design with two input polygons. ## Release Management * Affected package(s): Boolean_set_operations_2, Surface_sweep, Arrangement_on_surface_2 * Feature/Small Feature (if any): [here](https://cgalwiki.geometryfactory.com/CGAL/Members/wiki/Features/Small_Features/do_intersect_polygon_2_predicates_only) * Link to compiled documentation (obligatory for small feature) [*wrong link name to be changed*](httpssss://wrong_URL_to_be_changed/Manual/Pkg) * License and copyright ownership: TAU
2 parents 583a836 + 7e1f685 commit 1069678

39 files changed

+2893
-2649
lines changed
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
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

Comments
 (0)