Loading [MathJax]/extensions/tex2jax.js

Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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