Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

CrossingMinimalRegion.h
Go to the documentation of this file.
1 
31 #pragma once
32 
33 #ifdef OGDF_INCLUDE_CGAL
34 
35 # include <ogdf/basic/Logger.h>
43 
44 # include <limits>
45 
46 # include <CGAL/Min_circle_2.h>
47 # include <CGAL/Min_circle_2_traits_2.h>
48 
49 namespace ogdf {
50 namespace internal {
51 namespace gcm {
52 namespace graph {
53 
54 template<typename Kernel, typename Graph>
55 class CrossingMinimalRegion {
56 private:
57  using Point = geometry::Point_t<Kernel>;
58  using Segment = geometry::LineSegment_t<Kernel>;
59  using Polygon = geometry::Polygon_t<Kernel>;
60  using Drawing = graph::GeometricDrawing<Kernel, Graph>;
61 
62  using Node = typename Graph::Node;
63  using Edge = typename Graph::Edge;
64 
65  using BD = BloatedDualGraph<Kernel>;
66 
67  static Segment get_segment(const Drawing& d, const Node& w, const Node& u,
68  const geometry::Rectangle_t<Kernel>& rect) {
69  OGDF_ASSERT(u != w);
70  using FT = typename Kernel::FT;
71  FT delta_x = (d.get_point(u).x() - d.get_point(w).x());
72  FT delta_y = (d.get_point(u).y() - d.get_point(w).y());
73 
74  geometry::Ray_t<Kernel> r(d.get_point(u), geometry::Vector_t<Kernel>(delta_x, delta_y));
75  double t = 0;
76  for (unsigned int i = 0; i < 4; ++i) {
77  t = std::max(t, CGAL::to_double(geometry::distance(rect.vertex(i), d.get_point(u))));
78  }
79  OGDF_ASSERT(t > 0);
80  Segment s = {d.get_point(u), d.get_point(u) + geometry::normalize(r.to_vector()) * t * 1.1};
81 
82  return s;
83  }
84 
85  static std::vector<int> generate_segments(const Drawing& d, const Node& v,
86  const std::vector<Node>& neighbors, const std::vector<Edge>& edges, BD& bd,
87  geometry::Rectangle_t<Kernel>& rect_box //limiting the area
88  ) {
89  const auto& g = d.get_graph();
90 
91  bd.segments.reserve(g.number_of_nodes() * v->degree() + edges.size());
92  std::vector<int> left_to_right_cost;
93 
94  std::set<Node> nodes;
95  std::set<Edge> sampled_edges;
96  for (auto e : edges) {
97  auto s = d.get_segment(e);
98  if (s.target() < s.source()) {
99  s = {s.target(), s.source()};
100  }
101 
102  OGDF_ASSERT(s.squared_length() > 0);
103  bd.segments.push_back(s);
104  nodes.insert(e->target());
105  nodes.insert(e->source());
106  sampled_edges.insert(e);
107 
108  left_to_right_cost.push_back(0);
109  for (auto w : neighbors) {
110  if (e->isIncident(w)) {
111  continue;
112  }
113  if (geometry::left_turn(s, d.get_point(w))) {
114  left_to_right_cost.back()++;
115  } else {
116  left_to_right_cost.back()--;
117  }
118  }
119  }
120  for (auto u : nodes) {
121  for (auto w : neighbors) {
122  if (u != w && u != v) {
123  auto s = get_segment(d, w, u, rect_box);
124  if (s.target() < s.source()) {
125  s = {s.target(), s.source()};
126  }
127  OGDF_ASSERT(s.squared_length() > 0);
128  bd.segments.push_back(s);
129 
130  left_to_right_cost.push_back(0);
131  for (auto e : g.edges(u)) {
132  if (sampled_edges.find(e) == sampled_edges.end()) {
133  continue;
134  }
135  auto x = e->opposite(u);
136  if (e->isIncident(w) || e->isIncident(v)) {
137  continue;
138  }
139  if (geometry::left_turn(s, d.get_point(x))) {
140  left_to_right_cost.back()--;
141  } else {
142  left_to_right_cost.back()++;
143  }
144  }
145  }
146  }
147  }
148  std::vector<Point> p_rect;
149  for (unsigned int i = 0; i < 4; ++i) {
150  double x = ogdf::randomNumber(0, INT_MAX) % 1000 / 1000.0;
151  double y = ogdf::randomNumber(0, INT_MAX) % 1000 / 1000.0;
152  x = y = 0;
153  p_rect.push_back(rect_box.vertex(i) + geometry::Vector_t<Kernel>(x, y));
154  }
155 
156  for (unsigned int i = 0; i < 4; ++i) {
157  Segment s(p_rect[i], p_rect[(i + 1) % 4]);
158 
159  if (s.target() < s.source()) {
160  s = {s.target(), s.source()};
161  }
162 
163  OGDF_ASSERT(s.squared_length() > 0);
164  bd.segments.push_back(s);
165  if (geometry::left_turn(s, d.get_point(v))) {
166  left_to_right_cost.push_back(
167  d.get_graph().number_of_edges() * d.get_graph().number_of_edges());
168  } else {
169  left_to_right_cost.push_back(
170  -d.get_graph().number_of_edges() * d.get_graph().number_of_edges());
171  }
172  }
173 
174  return left_to_right_cost;
175  }
176 
177  static bool check_segments(std::vector<Segment>& segments) {
178  bool valid = true;
179  auto f_check_point = [&](const Segment& s, const Point& p) {
180  if (s.has_on(p) && s.source() != p && s.target() != p) {
181  // p is an interior point on s
182  return false;
183  } else {
184  return true;
185  }
186  };
187  for (unsigned int i = 0; i < segments.size(); ++i) {
188  for (unsigned int j = i + 1; j < segments.size(); ++j) {
189  if (!f_check_point(segments[i], segments[j].source())) {
190  Logger::slout() << "[math] " << i << " " << j << "; " << segments[i] << " "
191  << segments[j] << std::endl;
192  valid = false;
193  }
194  if (!f_check_point(segments[i], segments[j].target())) {
195  Logger::slout() << "[math] " << i << " " << j << "; " << segments[i] << " "
196  << segments[j] << std::endl;
197  valid = false;
198  }
199  }
200  }
201  return valid;
202  }
203 
204  static typename BD::Node get_min_vertex(const BD& bd, const Point& p,
205  const std::vector<int>& left_to_right_cost) {
206  typename BD::Node min_node = bd.segm_to_node_range[left_to_right_cost.size()
207  - 4]; // minimal node id of the nodes that represent the canvas / rect
208 
209 
210  auto rep = geometry::find_representative_node(bd, p);
211 
212  typename BD::Node min_vertex = rep;
213  double min_weight = 0; // this value becomes negative, if we can improve...
214 
215  std::vector<typename BD::Node> parent(bd.number_of_nodes());
216  std::vector<typename BD::Edge> parent_edge(bd.number_of_nodes());
217 
218  auto f_weight = [&](typename BD::Node v, typename BD::Edge e) {
219  if (bd.is_face_edge(e) || bd.degree(v) == 2) {
220  return 0;
221  } else if (bd.is_left(v)) {
222  return left_to_right_cost[bd.node_to_segment[v]];
223  } else {
224  return -left_to_right_cost[bd.node_to_segment[v]];
225  }
226  };
227 
228  auto expand = [&](typename BD::Node w, typename BD::Edge e) {
229  bool bad_edge = w >= min_node && bd.edges[e] >= min_node; //TODO correct??
230  return !bad_edge;
231  };
232 
233  parent[rep] = rep;
234 
235  std::vector<typename BD::Node> queue;
236  std::vector<int> weight(bd.number_of_nodes(), 0);
237  std::vector<bool> visited(bd.number_of_nodes(), false); //TODO use flags?
238 
239  queue.push_back(rep);
240  weight[rep] = 0;
241  visited[rep] = true;
242 
243  auto handle_edge = [&](typename BD::Node v, typename BD::Edge e) {
244  typename BD::Node w = bd.edges[e];
245  OGDF_ASSERT(!visited[w] || v == w || weight[w] == weight[v] + f_weight(v, e));
246  if (!visited[w] && expand(v, e) && v != w) {
247  weight[w] = weight[v] + f_weight(v, e);
248  visited[w] = true;
249  queue.push_back(w);
250  parent[w] = v;
251  parent_edge[w] = e;
252  }
253  };
254 
255  while (!queue.empty()) {
256  typename BD::Node current = queue.back();
257  queue.pop_back();
258  if (weight[current] < min_weight) {
259  min_vertex = current;
260  min_weight = weight[current];
261  }
262 
263 
264  handle_edge(current, 3 * current);
265  handle_edge(current, 3 * current + 1);
266  handle_edge(current, 3 * current + 2);
267  }
268  return min_vertex;
269  }
270 
271 public:
272  BD bd;
273  std::vector<int> left_to_right_cost;
274 
275  void build_bd(const Drawing& d, const Node& v, const std::vector<Node>& neighbors,
276  const std::vector<Edge>& edges, geometry::Rectangle_t<Kernel>& rect_box,
277  unsigned int& arr_n_segs, unsigned int& nof_intersections_in_arr) {
278  bd.clear();
279  left_to_right_cost.clear();
280 
281  left_to_right_cost = generate_segments(d, v, neighbors, edges, bd, rect_box);
282  OGDF_ASSERT(check_segments(bd.segments));
283 
284 # ifdef OGDF_GEOMETRIC_CR_MIN_DEBUG
285  std::cout << "intersect..." << std::flush;
286 # endif
287  geometry::PlanarSubdivision<Kernel, false> ps;
288  bd.intersecting_segments = std::move(ps.subdivision(bd.segments));
289  arr_n_segs = bd.segments.size();
290  nof_intersections_in_arr = bd.intersecting_segments.size();
291 # ifdef OGDF_GEOMETRIC_CR_MIN_DEBUG
292  std::cout << "done" << std::endl;
293 
294  std::cout << "nof segments in bd: " << arr_n_segs << std::endl;
295  std::cout << "nof intersectsion in arr: " << nof_intersections_in_arr << std::endl;
296  std::cout << "construct bd..." << std::flush;
297 # endif
298  static geometry::BloatedDual<Kernel> bdc;
299  bdc.construct(bd);
300 # ifdef OGDF_GEOMETRIC_CR_MIN_DEBUG
301  std::cout << "done" << std::endl;
302 # endif
303  }
304 
305  Polygon compute(const Drawing& d, const Node& v, const std::vector<Node>& neighbors,
306  const std::vector<Edge>& edges, geometry::Rectangle_t<Kernel>& rect_box,
307  unsigned int& arr_n_segs, unsigned int& nof_intersections_in_arr) {
308  build_bd(d, v, neighbors, edges, rect_box, arr_n_segs, nof_intersections_in_arr);
309 
310  auto dr = geometry::BloatedDual<Kernel>::compute_drawing(bd);
311  auto min_vertex = get_min_vertex(bd, d.get_point(v), left_to_right_cost);
312  auto seq = geometry::extract_cell(bd, min_vertex);
313  auto opt_region = geometry::extract_polygon(bd.segments, seq);
314  return opt_region;
315  }
316 };
317 
318 }
319 }
320 }
321 }
322 
323 #endif
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
BloatedDual.h
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:54
extended_graph_alg.h
Declaration of extended graph algorithms.
ogdf::gml::Key::Node
@ Node
ogdf::gml::Key::Edge
@ Edge
CGALPlanarSubdivision.h
Logger.h
Contains logging functionality.
r
int r[]
Definition: hierarchical-ranking.cpp:8
backward::details::move
const T & move(const T &v)
Definition: backward.hpp:243
ExtractCellFromBloatedDual.h
ogdf::gml::Key::Point
@ Point
BoothLueker.h
Declaration of BoothLueker which implements a planarity test and planar embedding algorithm.
ogdf::randomNumber
int randomNumber(int low, int high)
Returns random integer between low and high (including).
Dijkstra.h
ogdf::Logger::slout
static std::ostream & slout(Level level=Level::Default)
stream for logging-output (global)
Definition: Logger.h:191
PlanarSubdivision.h