Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

PlanarSubdivision.h
Go to the documentation of this file.
1 
31 #pragma once
32 
33 #ifdef OGDF_INCLUDE_CGAL
34 
41 
42 # include <CGAL/Exact_predicates_exact_constructions_kernel.h>
43 
44 # ifndef OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE
45 # define OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE false
46 # endif
47 
48 namespace ogdf {
49 namespace internal {
50 namespace gcm {
51 namespace geometry {
52 
53 
54 struct Intersection {
55  Intersection(unsigned int _seg_a, unsigned int _seg_b) : seg_a(_seg_a), seg_b(_seg_b) {
56  //nothing to
57  }
58 
59  unsigned int seg_a = -1; // first segment id
60  unsigned int seg_b = -1; // second segment id
61  unsigned int pos_on_a = -1; // ordered position on segment a
62  unsigned int pos_on_b = -1; // ordered position on segment b
63  bool proper = true; // is a proper intersection , i.e.,
64  // intersection point is an interior point of both segments;
65  bool is_source = false;
66  bool is_target = false;
67 
68  bool is_incident(const unsigned int segment) const {
69  return seg_a == segment || seg_b == segment;
70  }
71 
72  unsigned int opposite(const unsigned int segment) const {
73  if (seg_a == segment) {
74  return seg_b;
75  } else {
76  return seg_a;
77  }
78  }
79 
80  unsigned int pos(const unsigned int segment) const {
81  if (seg_a == segment) {
82  return pos_on_a;
83  } else {
84  return pos_on_b;
85  }
86  }
87 };
88 
91 template<typename Kernel, bool OPEN = true>
92 class PlanarSubdivision {
93 private:
94  using LineSegment = geometry::LineSegment_t<Kernel>;
95  using Point = geometry::Point_t<Kernel>;
96  using Polygon = geometry::Polygon_t<Kernel>;
97  using Line = geometry::Line_t<Kernel>;
98  using Ray = geometry::Ray_t<Kernel>;
99  using Direction = geometry::Direction_t<Kernel>;
100 
101  using ExactKernel = CGAL::Exact_predicates_exact_constructions_kernel;
102  using ExactLineSegment = geometry::LineSegment_t<ExactKernel>;
103  using ExactPoint = geometry::Point_t<ExactKernel>;
104 
105 
106  enum class EventType { Start, End };
107 
108  struct Event {
109  Point p;
110  unsigned int segment_id;
111  EventType event;
112 
113  Event(Point _p, unsigned int _id, EventType _ev) : p(_p), segment_id(_id), event(_ev) {
114  //nothing to do
115  }
116  };
117 
118 
119 public:
120  using LCGEdge = std::tuple<unsigned int, unsigned int, unsigned int>;
121 
126  template<typename IntersectionEvent>
127  void sweep(std::vector<LineSegment>& segments, IntersectionEvent&& intersection_event) {
128  std::vector<unsigned int> segment_to_active(segments.size(), -1);
129  std::vector<unsigned int> active;
130 
131  auto add_to_active = [&](unsigned int segment_id) {
132  segment_to_active[segment_id] = active.size();
133  active.push_back(segment_id);
134  };
135 
136  auto remove_from_active = [&](unsigned int segment_id) {
137  unsigned int active_id = segment_to_active[segment_id];
138  std::swap(active[active_id], active.back());
139  segment_to_active[active[active_id]] = active_id;
140  active.pop_back();
141  segment_to_active[segment_id] = -1;
142  };
143  std::vector<Event> events;
144  events.reserve(2 * segments.size());
145 
146 
147  for (unsigned int i = 0; i < segments.size(); ++i) {
148  Event ev_start(std::min(segments[i].source(), segments[i].target()), i, EventType::Start);
149  Event ev_end(std::max(segments[i].source(), segments[i].target()), i, EventType::End);
150 
151  events.push_back(ev_start);
152  events.push_back(ev_end);
153  }
154 
155 
156  std::sort(events.begin(), events.end(), [&](const Event& a, const Event& b) -> bool {
157  return a.p < b.p || (a.p == b.p && a.event == EventType::Start);
158  });
159 
160 
161  for (const Event& e : events) {
162  auto& new_segment = segments[e.segment_id];
163  if (e.event == EventType::Start) {
164  for (unsigned int active_id : active) {
165  OGDF_ASSERT(active_id < segments.size());
166  auto& active_segment = segments[active_id];
167 
168  if (OPEN && geometry::do_intersect_open(new_segment, active_segment)) {
169  intersection_event(e.segment_id, active_id);
170  }
171 
172  if (!OPEN && CGAL::do_intersect(new_segment, active_segment)) {
173  intersection_event(e.segment_id, active_id);
174  }
175  }
176  add_to_active(e.segment_id);
177  } else {
178  remove_from_active(e.segment_id);
179  }
180  }
181  }
182 
183  //robustness depends on kernel
184  void subdivision(std::vector<LineSegment>& segment,
185  std::vector<Point>& intersections // node_to_point
186  ,
187  std::vector<LCGEdge>& edge_list) {
188  //compute intersections
189  std::vector<std::vector<unsigned int>> intersections_of_segment(segment.size());
190 
191  //TODO handle start and end points;
192 
193  auto intersection_event = [&](unsigned int seg_1, unsigned int seg_2) {
194  //TODO handle collinearity?
195 
196  unsigned int v = intersections.size();
197 
198  intersections_of_segment[seg_1].push_back(v);
199  intersections_of_segment[seg_2].push_back(v);
200 
201  Point is = geometry::intersect(segment[seg_1], segment[seg_2]);
202  intersections.push_back(is);
203 
204  OGDF_ASSERT(CGAL::squared_distance(segment[seg_1], is) < 1);
205  OGDF_ASSERT(CGAL::squared_distance(segment[seg_2], is) < 1);
206 
207  OGDF_ASSERT(OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE || segment[seg_1].has_on(is));
208  OGDF_ASSERT(OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE || segment[seg_2].has_on(is));
209  };
210 
211  for (unsigned int i = 0; i < segment.size(); ++i) {
212  auto& s = segment[i];
213  intersections_of_segment[i].push_back(intersections.size());
214  intersections.push_back(s.source());
215  intersections_of_segment[i].push_back(intersections.size());
216  intersections.push_back(s.target());
217  }
218  sweep(segment, intersection_event);
219 
220  //identify and remove duplication of intersections
221 
222  datastructure::UnionFind node_mapping(intersections.size());
223  node_mapping.all_to_singletons();
224 
225  std::vector<unsigned int> same(intersections.size(), 0);
226  for (unsigned int i = 0; i < same.size(); ++i) {
227  same[i] = i;
228  }
229 
230  std::sort(same.begin(), same.end(),
231  [&](unsigned int a, unsigned int b) { return intersections[a] < intersections[b]; });
232 
233  for (unsigned int i = 0; i + 1 < same.size(); ++i) {
234  unsigned int u = same[i];
235  unsigned int v = same[i + 1];
236  if (intersections[u] == intersections[v]) {
237  node_mapping.merge(u, v);
238  }
239  }
240 
241  // build planar arrangement
242  for (unsigned int i = 0; i < segment.size(); ++i) {
243  auto& is = intersections_of_segment[i];
244  //intersections += is.size();
245  std::sort(is.begin(), is.end(), [&](const unsigned int a, unsigned int b) {
246  const Point& p_a = intersections[a];
247  const Point& p_b = intersections[b];
248 
249  auto d_a = CGAL::squared_distance(segment[i].source(), p_a);
250  auto d_b = CGAL::squared_distance(segment[i].source(),
251  p_b); //order a long line with respect to source
252  return d_a < d_b;
253  });
254  for (unsigned int j = 0; j + 1 < is.size(); ++j) {
255  unsigned int u = node_mapping[is[j]];
256  unsigned int v = node_mapping[is[j + 1]];
257 
258  if (u != v) {
259  OGDF_ASSERT(OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE
260  || segment[i].has_on(intersections[u]));
261  OGDF_ASSERT(OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE
262  || segment[i].has_on(intersections[v]));
263 
264  edge_list.push_back(LCGEdge(u, v, i));
265  }
266  }
267  }
268  }
269 
270  std::vector<Intersection> subdivision(std::vector<LineSegment>& segment) {
271  //compute intersections
272  std::vector<Intersection> intersecting_segments;
273  //TODO handle start and end points;
274 
275  auto intersection_event = [&](unsigned int seg_1, unsigned int seg_2) {
276  intersecting_segments.push_back({seg_1, seg_2});
277  };
278 
279  sweep(segment, intersection_event);
280  return intersecting_segments;
281  }
282 };
283 
284 
285 }
286 }
287 }
288 }
289 
290 #endif
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::Direction
Direction
Definition: basic.h:150
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:66
Minisat::Internal::sort
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:57
UnionFind.h
Ray.h
LineSegment.h
Line.h
Polygon.h
ogdf::gml::Key::Point
@ Point
Direction.h