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
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
49namespace ogdf {
50namespace internal {
51namespace gcm {
52namespace graph {
53
54template<typename Kernel, typename Graph>
56private:
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
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) {
260 min_weight = weight[current];
261 }
262
263
265 handle_edge(current, 3 * current + 1);
266 handle_edge(current, 3 * current + 2);
267 }
268 return min_vertex;
269 }
270
271public:
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
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) {
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
Declaration of BoothLueker which implements a planarity test and planar embedding algorithm.
Contains logging functionality.
Declaration of extended graph algorithms.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:41
int randomNumber(int low, int high)
Returns random integer between low and high (including).
int r[]
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.