Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
Circle.h
Go to the documentation of this file.
1
31#pragma once
32
33#ifdef OGDF_INCLUDE_CGAL
34
37
38# include <functional>
39# include <iomanip>
40# include <vector>
41
42# include <CGAL/Algebraic_kernel_for_circles_2_2.h>
43# include <CGAL/Boolean_set_operations_2.h>
44# include <CGAL/Circle_2.h>
45# include <CGAL/Circular_kernel_2.h>
46# include <CGAL/General_polygon_set_2.h>
47# include <CGAL/Gps_circle_segment_traits_2.h>
48
49namespace ogdf {
50namespace internal {
51namespace gcm {
52
53namespace geometry {
54using namespace tools;
55
56template<typename kernel>
57using Circle_t = CGAL::Circle_2<kernel>;
58
59template<typename kernel>
60typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Point_2
61convert(const typename kernel::Point_2& p) {
62 return {p.x(), p.y()};
63}
64
65template<typename kernel>
66typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Circle_2
68 return {{circle.center().x(), circle.center().y()}, circle.squared_radius()};
69}
70
71template<typename kernel>
72typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Line_2
73convert(const geometry::Line_t<kernel>& line) {
74 return {line.a(), line.b(), line.c()};
75}
76
77template<typename kernel>
78typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Segment_2
79convert(const geometry::LineSegment_t<kernel>& ls) {
80 return {convert<kernel>(ls.source()), convert<kernel>(ls.target())};
81}
82
83template<typename kernel>
85 if (circle.has_on_boundary(ls.source())) {
86 return true;
87 } else if (circle.has_on_unbounded_side(ls.source()) && circle.has_on_bounded_side(ls.target())) {
88 return true;
89 } else if (circle.has_on_unbounded_side(ls.target()) && circle.has_on_bounded_side(ls.source())) {
90 return true;
91 } else {
92 return false;
93 }
94}
95
96template<typename kernel>
97void intersect(const Circle_t<kernel>& circle, const LineSegment_t<kernel>& ls,
99 using AKernel = CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>;
100 using CKernel = CGAL::Circular_kernel_2<kernel, AKernel>;
101 using CCircle = typename CKernel::Circle_2;
102 using CLine = typename CKernel::Line_2;
103
104
105 auto c = convert(circle);
106 auto l = convert(ls);
107 typename CKernel::Line_arc_2 line_arc(l);
108
109 OGDF_ASSERT(geometry::do_intersect(c, l));
110 using IS_Result = typename CGAL::CK2_Intersection_traits<CKernel, CCircle, CLine>::type;
111
112 std::vector<IS_Result> is;
113 CGAL::intersection(c, line_arc, std::back_inserter(is));
114
115 using R = std::pair<CGAL::Circular_arc_point_2<CKernel>, unsigned int>;
116
117 if (is.size() > 0) {
118 auto is_1 = boost::get<R>(&is[0]);
119 intersection_1 = {CGAL::to_double(is_1->first.x()), CGAL::to_double(is_1->first.y())};
120 }
121 if (is.size() > 1) {
122 auto is_2 = boost::get<R>(&is[1]);
123 intersection_2 = {CGAL::to_double(is_2->first.x()), CGAL::to_double(is_2->first.y())};
124 }
125}
126
127template<typename kernel>
128void intersect(const Circle_t<kernel>& c1, const Circle_t<kernel>& c2,
130 using AKernel = CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>;
131 using CKernel = CGAL::Circular_kernel_2<kernel, AKernel>;
132 using CCircle = typename CKernel::Circle_2;
133
134 auto cc1 = convert(c1);
135 auto cc2 = convert(c2);
136 OGDF_ASSERT(CGAL::do_intersect(c1, c2));
137
138 using IS_Result = typename CGAL::CK2_Intersection_traits<CKernel, CCircle, CCircle>::type;
139 using R = std::pair<CGAL::Circular_arc_point_2<CKernel>, unsigned int>;
140
141 std::vector<IS_Result> is;
142 CGAL::intersection(cc1, cc2, std::back_inserter(is));
143
144 if (is.size() > 0) {
145 auto is_1 = boost::get<R>(&is[0]);
146 if (is_1) {
147 intersection_1 = {CGAL::to_double(is_1->first.x()), CGAL::to_double(is_1->first.y())};
148 }
149 }
150
151 if (is.size() > 1) {
152 auto is_2 = boost::get<R>(&is[1]);
153 if (is_2) {
154 intersection_2 = {CGAL::to_double(is_2->first.x()), CGAL::to_double(is_2->first.y())};
155 }
156 }
157}
158
159template<typename kernel>
160bool contains(const Circle_t<kernel>& c, const Point_t<kernel>& p) {
161 return c.has_on_boundary(p) || c.has_on_bounded_side(p);
162}
163
164template<typename kernel>
165class CircleOperation_t {
166private:
167 using Point = Point_t<kernel>;
169 using Circle = Circle_t<kernel>;
170
171protected:
172 template<typename F>
173 void intersect_pair(const Circle& c_1, const Circle& c_2, F&& f) const {
174 if (CGAL::do_intersect(c_1, c_2)) {
175 Point is_1, is_2;
176 geometry::intersect(c_1, c_2, is_1, is_2);
177 f(is_1);
178 if (is_1 != is_2) {
179 f(is_2);
180 }
181 }
182 }
183
184public:
185 const Circle& circle_1;
186 const Circle& circle_2;
187
190 /*nothing to do*/
191 }
192
193 virtual ~CircleOperation_t() { /*nothing to do*/
194 }
195
196 virtual void intersect(const LineSegment&, std::function<void(const Point)>&&) const = 0;
197 virtual void intersect(const CircleOperation_t<kernel>&,
198 std::function<void(const Point)>&&) const = 0;
199 virtual bool do_intersect(const LineSegment_t<kernel>&) const = 0;
200 virtual bool contains(const Point_t<kernel>&) const = 0;
201 virtual bool contains(const Circle& other, const Point& p) const = 0;
202
203 friend std::ostream& operator<<(std::ostream& os, const CircleOperation_t<kernel>& c) {
204 os << c.circle_1 << " " << c.circle_2;
205 return os;
206 }
207};
208
209template<typename kernel>
210class IntersectingCircles_t : public CircleOperation_t<kernel> {
211private:
213 using parent = CircleOperation;
215 using Circle = Circle_t<kernel>;
217 using Point = Point_t<kernel>;
218
219 template<typename F>
220 void intersect_circle(const LineSegment& ls, const Circle& c, const Circle& other, F&& f) const {
221 if (geometry::do_intersect(c, ls)) {
222 Point is_1, is_2;
223 geometry::intersect(c, ls, is_1, is_2);
224 //intersection is definetyl in c
225 if (contains(other, is_1)) {
226 f(is_1);
227 }
228 if (is_1 != is_2 && contains(other, is_2) && is_on(ls, is_2)) {
229 f(is_2);
230 }
231 }
232 }
233
234public:
235 bool contains(const Circle& other, const Point& p) const {
236 return geometry::contains(other, p);
237 }
238
240 : parent(circle_1, circle_2) {
241 /*nothing to do*/
242 }
243
244 void intersect(const CircleOperation& op, std::function<void(const Point)>&& f) const {
245 parent::intersect_pair(parent::circle_1, op.circle_1, [&](const Point& p) {
246 if (contains(parent::circle_2, p) && op.contains(op.circle_2, p)) {
247 f(p);
248 }
249 });
250
251 parent::intersect_pair(parent::circle_1, op.circle_2, [&](const Point& p) {
252 if (contains(parent::circle_2, p) && op.contains(op.circle_1, p)) {
253 f(p);
254 }
255 });
256
257 parent::intersect_pair(parent::circle_2, op.circle_1, [&](const Point& p) {
258 if (contains(parent::circle_1, p) && op.contains(op.circle_2, p)) {
259 f(p);
260 }
261 });
262
263 parent::intersect_pair(parent::circle_2, op.circle_2, [&](const Point& p) {
264 if (contains(parent::circle_1, p) && op.contains(op.circle_1, p)) {
265 f(p);
266 }
267 });
268
269 parent::intersect_pair(parent::circle_1, parent::circle_2, [&](const Point& p) {
270 if (op.contains(p)) {
271 f(p);
272 }
273 });
274
275 parent::intersect_pair(op.circle_1, op.circle_2, [&](const Point& p) {
276 if (contains(p)) {
277 f(p);
278 }
279 });
280
281 if (op.contains(parent::circle_1.center()) && contains(parent::circle_1.center())) {
282 f(parent::circle_1.center());
283 }
284 if (op.contains(op.circle_1.center()) && contains(op.circle_1.center())) {
285 f(op.circle_1.center());
286 }
287 }
288
289 void intersect(const LineSegment& ls, std::function<void(const Point)>&& f) const {
290 intersect_circle(ls, parent::circle_1, parent::circle_2, f);
291 intersect_circle(ls, parent::circle_2, parent::circle_1, f);
292 }
293
294 bool do_intersect(const LineSegment& ls) const {
295 return geometry::do_intersect(parent::circle_1, ls)
296 && geometry::do_intersect(parent::circle_2, ls);
297 }
298
299 bool contains(const Point& p) const {
300 return geometry::contains(parent::circle_1, p) && geometry::contains(parent::circle_2, p);
301 }
302};
303
304template<typename kernel>
305class CombinedCircles_t : public CircleOperation_t<kernel> {
306private:
308 using parent = CircleOperation;
310 using Circle = Circle_t<kernel>;
312 using Point = Point_t<kernel>;
313
314 template<typename F>
315 void intersect_circle(const LineSegment& ls, const Circle& c, F&& f) const {
316 if (geometry::do_intersect(c, ls)) {
317 Point is_1, is_2;
318 geometry::intersect(c, ls, is_1, is_2);
319 f(is_1);
320 if (is_1 != is_2 && is_on(ls, is_2)) {
321 f(is_2);
322 }
323 }
324 }
325
326public:
328 /*nothing to do*/
329 }
330
331 void intersect(const LineSegment& ls, std::function<void(const Point)>&& f) const {
332 intersect_circle(ls, parent::circle_1, f);
333 intersect_circle(ls, parent::circle_2, f);
334 }
335
336 // TODO assumes circle operation is of same type....
337 void intersect(const CircleOperation& op, std::function<void(const Point)>&& f) const {
338 parent::intersect_pair(parent::circle_1, op.circle_1, f);
339 parent::intersect_pair(parent::circle_1, op.circle_2, f);
340 parent::intersect_pair(parent::circle_2, op.circle_1, f);
341 parent::intersect_pair(parent::circle_2, op.circle_2, f);
342
343 parent::intersect_pair(parent::circle_1, parent::circle_2, [&](const Point& p) {
344 if (op.contains(p)) {
345 f(p);
346 }
347 });
348 parent::intersect_pair(op.circle_1, op.circle_2, [&](const Point& p) {
349 if (contains(p)) {
350 f(p);
351 }
352 });
353
354 if (op.contains(parent::circle_1.center())) {
355 f(parent::circle_1.center());
356 }
357
358 if (op.contains(parent::circle_2.center())) {
359 f(parent::circle_1.center());
360 }
361
362 if (contains(op.circle_1.center())) {
363 f(op.circle_1.center());
364 }
365
366 if (contains(op.circle_2.center())) {
367 f(op.circle_2.center());
368 }
369 }
370
371 bool do_intersect(const LineSegment& ls) const {
372 return geometry::do_intersect(parent::circle_1, ls)
373 || geometry::do_intersect(parent::circle_2, ls);
374 }
375
376 bool contains(const Circle&, const Point&) const { return true; }
377
378 bool contains(const Point& p) const {
379 return geometry::contains(parent::circle_1, p) || geometry::contains(parent::circle_2, p);
380 }
381};
382
383template<typename Kernel>
384typename CGAL::Gps_circle_segment_traits_2<Kernel>::General_polygon_2 construct_polygon_from_circle(
385 const Circle_t<Kernel>& circle) {
386 using Traits_2 = CGAL::Gps_circle_segment_traits_2<Kernel>;
387 using Polygon_2 = typename Traits_2::General_polygon_2;
388 using Curve_2 = typename Traits_2::Curve_2;
389 using X_monotone_curve_2 = typename Traits_2::X_monotone_curve_2;
390
391 //Subdivide the circle into two x-monotone arcs.
394 std::list<CGAL::Object> objects;
395 traits.make_x_monotone_2_object()(curve, std::back_inserter(objects));
396 OGDF_ASSERT(objects.size() == 2);
397 // Construct the polygon.
400 std::list<CGAL::Object>::iterator iter;
401 for (iter = objects.begin(); iter != objects.end(); ++iter) {
402 CGAL::assign(arc, *iter);
403 pgn.push_back(arc);
404 }
405 return pgn;
406}
407
408} //namespace
409}
410}
411}
412
413#endif
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:41
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.
std::ostream & operator<<(std::ostream &os, const ogdf::Array< E, INDEX > &a)
Prints array a to output stream os.
Definition Array.h:978