Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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 
49 namespace ogdf {
50 namespace internal {
51 namespace gcm {
52 
53 namespace geometry {
54 using namespace tools;
55 
56 template<typename kernel>
57 using Circle_t = CGAL::Circle_2<kernel>;
58 
59 template<typename kernel>
60 typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Point_2
61 convert(const typename kernel::Point_2& p) {
62  return {p.x(), p.y()};
63 }
64 
65 template<typename kernel>
66 typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Circle_2
67 convert(const Circle_t<kernel>& circle) {
68  return {{circle.center().x(), circle.center().y()}, circle.squared_radius()};
69 }
70 
71 template<typename kernel>
72 typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Line_2
73 convert(const geometry::Line_t<kernel>& line) {
74  return {line.a(), line.b(), line.c()};
75 }
76 
77 template<typename kernel>
78 typename CGAL::Circular_kernel_2<kernel, CGAL::Algebraic_kernel_for_circles_2_2<typename kernel::FT>>::Segment_2
79 convert(const geometry::LineSegment_t<kernel>& ls) {
80  return {convert<kernel>(ls.source()), convert<kernel>(ls.target())};
81 }
82 
83 template<typename kernel>
84 bool do_intersect(const Circle_t<kernel>& circle, const LineSegment_t<kernel>& ls) {
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 
96 template<typename kernel>
97 void intersect(const Circle_t<kernel>& circle, const LineSegment_t<kernel>& ls,
98  Point_t<kernel>& intersection_1, Point_t<kernel>& intersection_2) {
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));
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 
127 template<typename kernel>
128 void intersect(const Circle_t<kernel>& c1, const Circle_t<kernel>& c2,
129  Point_t<kernel>& intersection_1, Point_t<kernel>& intersection_2) {
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 
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 
159 template<typename kernel>
160 bool 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 
164 template<typename kernel>
165 class CircleOperation_t {
166 private:
167  using Point = Point_t<kernel>;
168  using LineSegment = LineSegment_t<kernel>;
169  using Circle = Circle_t<kernel>;
170 
171 protected:
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 
184 public:
185  const Circle& circle_1;
186  const Circle& circle_2;
187 
188  CircleOperation_t(const Circle& circle1, const Circle& circle2)
189  : circle_1(circle1), circle_2(circle2) {
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 
209 template<typename kernel>
210 class IntersectingCircles_t : public CircleOperation_t<kernel> {
211 private:
212  using CircleOperation = CircleOperation_t<kernel>;
213  using parent = CircleOperation;
214  using ICOp = IntersectingCircles_t<kernel>;
215  using Circle = Circle_t<kernel>;
216  using LineSegment = LineSegment_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 
234 public:
235  bool contains(const Circle& other, const Point& p) const {
236  return geometry::contains(other, p);
237  }
238 
239  IntersectingCircles_t(const Circle& circle_1, const Circle& circle_2)
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 
304 template<typename kernel>
305 class CombinedCircles_t : public CircleOperation_t<kernel> {
306 private:
307  using CircleOperation = CircleOperation_t<kernel>;
308  using parent = CircleOperation;
309  using CCOp = CombinedCircles_t<kernel>;
310  using Circle = Circle_t<kernel>;
311  using LineSegment = LineSegment_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 
326 public:
327  CombinedCircles_t(const Circle& circle_1, const Circle& circle_2) : parent(circle_1, circle_2) {
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 
383 template<typename Kernel>
384 typename 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.
392  Traits_2 traits;
393  Curve_2 curve(circle);
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.
398  Polygon_2 pgn;
399  X_monotone_curve_2 arc;
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
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
math.h
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:54
backward::Color::type
type
Definition: backward.hpp:1716
ogdf::operator<<
std::ostream & operator<<(std::ostream &os, const ogdf::Array< E, INDEX > &a)
Prints array a to output stream os.
Definition: Array.h:978
LineSegment.h
ogdf::gml::Key::Point
@ Point
ogdf::graphml::Attribute::R
@ R