Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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.