33 #ifdef OGDF_INCLUDE_CGAL
37 # ifdef OGDF_GEOMETRIC_CR_MIN_DEBUG
39 # define OGDF_GEOMETRIC_BD_ECHO(x) Logger::slout() << "[BD] " << x << std::endl;
41 # define OGDF_GEOMETRIC_BD_ECHO(x)
49 template<
typename Kernel,
bool parallel = false>
52 using Point = geometry::Point_t<Kernel>;
53 using Segment = LineSegment_t<Kernel>;
54 using ExactKernel = CGAL::Simple_cartesian<CGAL::Gmpq>;
56 using BD = graph::BloatedDualGraph<Kernel>;
57 using Node =
typename BD::Node;
58 using Edge =
typename BD::Edge;
59 using LocalIntersection =
typename BD::LocalIntersection;
61 inline bool consider_equal(
const Point& p,
const Point& q)
const {
return p == q; }
63 bool has_point_on_segment(
const Segment& reference,
const Point& p) {
64 if (reference.has_on(p)) {
66 }
else if (consider_equal(p, reference.supporting_line().projection(p))) {
67 auto ex_p = geometry::cast<ExactKernel>(p);
68 auto ex_segment = geometry::cast<ExactKernel>(reference);
69 return ex_segment.has_on(ex_p);
75 inline bool has_endpoint_on_segment(
const Segment& reference,
const Segment& opposite) {
76 return has_point_on_segment(reference, opposite.source())
77 || has_point_on_segment(reference, opposite.target());
80 std::set<std::pair<unsigned int, unsigned int>> seen;
82 void assign_intersections_to_segment(
const std::vector<Segment>& segments,
83 const std::vector<Intersection>& intersecting_segments,
84 std::vector<std::vector<unsigned int>>& _segment_to_intersections,
85 std::vector<Point>& intersections) {
88 for (
unsigned int i = 0; i < intersecting_segments.size(); ++i) {
89 auto& pair = intersecting_segments[i];
90 if (seen.find({pair.seg_a, pair.seg_b}) == seen.end()
91 && seen.find({pair.seg_b, pair.seg_a}) == seen.end()) {
92 _segment_to_intersections[pair.seg_a].push_back(i);
93 if (pair.seg_a != pair.seg_b) {
94 _segment_to_intersections[pair.seg_b].push_back(i);
97 auto& seg_a = segments[pair.seg_a];
98 auto& seg_b = segments[pair.seg_b];
101 intersections.push_back(seg_a.source());
102 }
else if (pair.is_target) {
104 intersections.push_back(seg_a.target());
105 }
else if (geometry::have_common_endpoints(seg_a, seg_b)) {
106 intersections.push_back(geometry::get_common_endpoint(seg_a, seg_b));
108 Point p_a = geometry::intersect(seg_a, seg_b);
109 intersections.push_back(p_a);
115 void sort_intersections_along_segment(
const std::vector<Segment>& segments,
116 const std::vector<Intersection>& intersecting_segments,
117 std::vector<std::vector<unsigned int>>& _segment_to_intersections,
118 std::vector<Point>& intersections) {
119 for (
unsigned int i = 0; i < _segment_to_intersections.size(); ++i) {
120 auto& is = _segment_to_intersections[i];
122 auto compare = [&](
const unsigned int a,
const unsigned int b) {
123 const Point& p_a = intersections[a];
125 const Point& p_b = intersections[b];
127 auto d_a = CGAL::squared_distance(segments[i].source(), p_a);
128 auto d_b = CGAL::squared_distance(segments[i].source(),
131 bool comp = d_a < d_b;
137 std::sort(is.begin(), is.end(), compare);
139 std::sort(is.begin(), is.end(), compare);
144 std::vector<unsigned int> left_intersections;
145 std::vector<unsigned int> right_intersections;
151 void clean_up(
unsigned int segment,
const std::vector<Segment>& segments,
152 const std::vector<Intersection>& intersecting_segments
154 const std::vector<Point>& intersections
156 const std::vector<unsigned int>& intersections_along_segment
158 std::vector<LocalIntersection>& clean_intersecting_segments
160 auto is_proper = [&](
const Segment& _segment,
const Point& p) {
161 return !consider_equal(_segment.source(), p) && !consider_equal(_segment.target(), p)
162 && !has_point_on_segment(_segment, p);
165 auto is_proper_left_turn = [&](
const Segment& _segment,
const Point& p) {
166 return is_proper(_segment, p) && geometry::left_turn(_segment, p);
170 auto is_proper_right_turn = [&](
const Segment& _segment,
const Point& p) {
171 return is_proper(_segment, p) && geometry::right_turn(_segment, p);
175 for (
unsigned int j = 0; j
176 < intersections_along_segment.size();) {
177 left_intersections.clear();
178 right_intersections.clear();
180 const unsigned int ref_intersection = j;
182 int self_intersection_id = -1;
184 OGDF_GEOMETRIC_BD_ECHO(
"reference: " << segment);
186 while (j < intersections_along_segment.size()
187 && consider_equal(intersections[intersections_along_segment[ref_intersection]],
188 intersections[intersections_along_segment[j]])) {
190 unsigned int intersection_id = intersections_along_segment[j];
191 unsigned int opp = intersecting_segments[intersection_id].opposite(segment);
193 bool is_left_turn = is_proper_left_turn(segments[segment], segments[opp].source())
194 || is_proper_left_turn(segments[segment], segments[opp].target());
195 bool is_right_turn = is_proper_right_turn(segments[segment], segments[opp].source())
196 || is_proper_right_turn(segments[segment], segments[opp].target());
199 if (segment == opp) {
200 self_intersection_id = intersection_id;
201 }
else if (!is_left_turn && !is_right_turn) {
203 left_intersections.push_back(intersection_id);
204 right_intersections.push_back(intersection_id);
207 left_intersections.push_back(intersection_id);
211 right_intersections.push_back(intersection_id);
218 if (left_intersections.empty() && right_intersections.empty()) {
219 left_intersections.push_back(self_intersection_id);
222 if (left_intersections.size() > 1) {
223 std::sort(left_intersections.begin(), left_intersections.end(),
224 [&](
const unsigned int a,
const unsigned int b) {
225 auto& seg_a = segments[intersecting_segments[a].opposite(segment)];
226 auto& seg_b = segments[intersecting_segments[b].opposite(segment)];
230 if (is_proper_left_turn(segments[segment], seg_a.source())
231 || segments[segment].source() == seg_a.target()) {
235 if (is_proper_left_turn(segments[segment], seg_b.source())
236 || segments[segment].source() == seg_b.target()) {
240 return geometry::right_turn(seg_a.to_vector() * sign_a,
241 seg_b.to_vector() * sign_b);
246 if (right_intersections.size() > 1) {
247 std::sort(right_intersections.begin(), right_intersections.end(),
248 [&](
const unsigned int a,
const unsigned int b) {
249 auto& seg_a = segments[intersecting_segments[a].opposite(segment)];
250 auto& seg_b = segments[intersecting_segments[b].opposite(segment)];
255 if (is_proper_right_turn(segments[segment], seg_a.source())
256 || segments[segment].source() == seg_a.target()) {
260 if (is_proper_right_turn(segments[segment], seg_b.source())
261 || segments[segment].source() == seg_b.target()) {
265 return geometry::left_turn(seg_a.to_vector() * sign_a,
266 seg_b.to_vector() * sign_b);
270 OGDF_ASSERT(!left_intersections.empty() || !right_intersections.empty());
271 LocalIntersection li;
272 li.is_end_point = self_intersection_id >= 0;
273 if (!left_intersections.empty()) {
274 li.left_intersection_ids[0] = left_intersections.front();
275 li.left_intersection_ids[1] = left_intersections.back();
278 if (!right_intersections.empty()) {
279 li.right_intersection_ids[0] = right_intersections.front();
280 li.right_intersection_ids[1] = right_intersections.back();
283 clean_intersecting_segments.push_back(li);
287 void handle_non_proper_intersection(BD& bd,
unsigned int ref_seg, LocalIntersection& li) {
288 if (li.left_is_valid()
289 && (bd.intersecting_segments[li.left_intersection_ids[0]].is_source
290 || bd.intersecting_segments[li.left_intersection_ids[0]].is_target)) {
294 OGDF_GEOMETRIC_BD_ECHO(
"---------------------------");
295 OGDF_GEOMETRIC_BD_ECHO(
"reference segment " << ref_seg);
300 bool intersection_is_source =
301 consider_equal(bd.segments[ref_seg].source(), bd.get_intersection_point(li));
302 bool intersection_is_target =
303 consider_equal(bd.segments[ref_seg].target(), bd.get_intersection_point(li));
304 bool proper = !intersection_is_source && !intersection_is_target;
306 bool source_is_left[2] = {
false,
false};
307 bool source_is_right[2] = {
false,
false};
309 if (li.left_is_valid()) {
310 unsigned int left_segment_id[2];
311 OGDF_GEOMETRIC_BD_ECHO(
"ref: " << ref_seg <<
"; " << bd.segments[ref_seg]);
312 OGDF_GEOMETRIC_BD_ECHO(
"intersection is source: " << intersection_is_source)
313 OGDF_GEOMETRIC_BD_ECHO(
"intersection is target: " << intersection_is_target)
314 OGDF_GEOMETRIC_BD_ECHO(
"proper: " << proper)
315 for (
unsigned int i = 0; i < 2; ++i) {
317 bd.intersecting_segments[li.left_intersection_ids[i]].opposite(ref_seg);
319 source_is_left[i] = !consider_equal(bd.segments[left_segment_id[i]].source(),
320 bd.get_intersection_point(li))
321 && geometry::left_turn(bd.segments[ref_seg],
322 bd.segments[left_segment_id[i]].source());
324 OGDF_GEOMETRIC_BD_ECHO(
"\t l" << left_segment_id[i] <<
"; "
325 << bd.segments[left_segment_id[i]] <<
": "
326 << source_is_left[i]);
329 if (proper || intersection_is_target) {
330 Node u1 = bd.first_left(ref_seg, li.left_intersection_ids[0]);
333 if (source_is_left[0]
334 || consider_equal(bd.segments[left_segment_id[0]].target(),
335 bd.get_intersection_point(li))) {
336 v1 = bd.first_right(left_segment_id[0], li.left_intersection_ids[0]);
338 v1 = bd.second_left(left_segment_id[0], li.left_intersection_ids[0]);
341 bd.add_edge(u1, v1,
true);
344 if (proper || intersection_is_source) {
345 Node u2 = bd.second_left(ref_seg, li.left_intersection_ids[0]);
348 if (source_is_left[1]
349 || consider_equal(bd.segments[left_segment_id[1]].target(),
350 bd.get_intersection_point(li))) {
351 v2 = bd.first_left(left_segment_id[1], li.left_intersection_ids[1]);
353 v2 = bd.second_right(left_segment_id[1], li.left_intersection_ids[1]);
356 bd.add_edge(u2, v2,
true);
360 Node u1 = bd.first_left(ref_seg, li.right_intersection_ids[0]);
361 Node v1 = bd.second_left(ref_seg, li.right_intersection_ids[0]);
362 bd.add_edge(u1, v1,
true);
363 }
else if (intersection_is_source) {
364 auto id = li.right_intersection_ids[0];
366 Node u1 = bd.second_left(ref_seg,
id);
368 unsigned int opp = bd.intersecting_segments[id].opposite(ref_seg);
369 if (consider_equal(bd.segments[opp].target(), bd.get_intersection_point(li))) {
370 v1 = bd.first_left(opp,
id);
372 v1 = bd.second_right(opp,
id);
375 bd.add_edge(u1, v1,
true);
377 }
else if (intersection_is_target) {
378 auto id = li.right_intersection_ids[1];
380 Node u1 = bd.first_left(ref_seg,
id);
382 unsigned int opp = bd.intersecting_segments[id].opposite(ref_seg);
383 if (consider_equal(bd.segments[opp].target(), bd.get_intersection_point(li))) {
384 v1 = bd.first_right(opp,
id);
386 v1 = bd.second_left(opp,
id);
389 bd.add_edge(u1, v1,
true);
392 if (li.right_is_valid()) {
393 unsigned int right_segment_id[2];
394 OGDF_GEOMETRIC_BD_ECHO(
"ref: " << ref_seg <<
"; " << bd.segments[ref_seg]);
395 for (
unsigned int i = 0; i < 2; ++i) {
396 right_segment_id[i] =
397 bd.intersecting_segments[li.right_intersection_ids[i]].opposite(ref_seg);
399 source_is_right[i] = !consider_equal(bd.segments[right_segment_id[i]].source(),
400 bd.get_intersection_point(li))
401 && geometry::right_turn(bd.segments[ref_seg],
402 bd.segments[right_segment_id[i]].source());
404 OGDF_GEOMETRIC_BD_ECHO(
"\t r" << right_segment_id[i] <<
"; "
405 << bd.segments[right_segment_id[i]] <<
": "
406 << source_is_right[i]);
409 if (proper || intersection_is_target) {
410 Node u1 = bd.first_right(ref_seg, li.right_intersection_ids[0]);
412 if (source_is_right[0]
413 || consider_equal(bd.segments[right_segment_id[0]].target(),
414 bd.get_intersection_point(li))) {
415 v1 = bd.first_left(right_segment_id[0], li.right_intersection_ids[0]);
417 v1 = bd.second_right(right_segment_id[0], li.right_intersection_ids[0]);
420 bd.add_edge(u1, v1,
true);
423 if (proper || intersection_is_source) {
424 Node u2 = bd.second_right(ref_seg, li.right_intersection_ids[0]);
427 if (source_is_right[1]
428 || consider_equal(bd.segments[right_segment_id[1]].target(),
429 bd.get_intersection_point(li))) {
430 v2 = bd.first_right(right_segment_id[1], li.right_intersection_ids[1]);
432 v2 = bd.second_left(right_segment_id[1], li.right_intersection_ids[1]);
435 bd.add_edge(u2, v2,
true);
438 Node u1 = bd.first_right(ref_seg, li.left_intersection_ids[0]);
439 Node v1 = bd.second_right(ref_seg, li.left_intersection_ids[0]);
440 bd.add_edge(u1, v1,
true);
442 }
else if (intersection_is_source) {
443 auto id = li.left_intersection_ids[0];
445 Node u1 = bd.second_right(ref_seg,
id);
447 unsigned int opp = bd.intersecting_segments[id].opposite(ref_seg);
448 if (consider_equal(bd.segments[opp].target(), bd.get_intersection_point(li))) {
449 v1 = bd.first_right(opp,
id);
451 v1 = bd.second_left(opp,
id);
454 bd.add_edge(u1, v1,
true);
455 }
else if (intersection_is_target) {
456 auto id = li.left_intersection_ids[1];
458 Node u1 = bd.first_right(ref_seg,
id);
460 unsigned int opp = bd.intersecting_segments[id].opposite(ref_seg);
461 if (consider_equal(bd.segments[opp].target(), bd.get_intersection_point(li))) {
462 v1 = bd.first_left(opp,
id);
464 v1 = bd.second_right(opp,
id);
467 bd.add_edge(u1, v1,
true);
471 inline void construct_graph(BD& bd) {
475 nof_threads = omp_get_max_threads();
477 # pragma omp parallel for num_threads(nof_threads)
478 for (
unsigned int i = 0; i < bd.segments.size(); ++i) {
479 for (
unsigned int j = 0; j < bd.segment_to_intersections[i].size(); ++j) {
480 handle_non_proper_intersection(bd, i, bd.segment_to_intersections[i][j]);
495 std::vector<std::vector<unsigned int>> segment_to_intersections;
497 void construct(BD& bd) {
499 segment_to_intersections.clear();
500 segment_to_intersections.resize(bd.segments.size());
502 for (
unsigned int i = 0; i < bd.segments.size(); ++i) {
503 Intersection s(i, i);
506 bd.intersecting_segments.push_back(s);
510 bd.intersecting_segments.push_back(s);
513 assign_intersections_to_segment(bd.segments, bd.intersecting_segments,
514 segment_to_intersections, bd.intersections);
516 sort_intersections_along_segment(bd.segments, bd.intersecting_segments,
517 segment_to_intersections, bd.intersections);
519 bd.segment_to_intersections.resize(bd.segments.size());
520 for (
unsigned int i = 0; i < bd.segments.size(); ++i) {
521 clean_up(i, bd.segments, bd.intersecting_segments, bd.intersections,
522 segment_to_intersections[i], bd.segment_to_intersections[i]);
524 || bd.segment_to_intersections[i].size() >= 1);
527 for (
unsigned int i = 0; i < bd.segment_to_intersections.size(); ++i) {
528 auto& is = bd.segment_to_intersections[i];
530 for (
unsigned int j = 0; j < is.size(); ++j) {
531 LocalIntersection& x = is[j];
533 auto set_pos = [&](
unsigned int intersection_id) {
534 if (intersection_id < bd.intersecting_segments.size()) {
535 auto& y = bd.intersecting_segments[intersection_id];
545 set_pos(x.left_intersection_ids[0]);
546 set_pos(x.left_intersection_ids[1]);
547 set_pos(x.right_intersection_ids[0]);
548 set_pos(x.right_intersection_ids[1]);
552 bd.segm_to_node_range.reserve(bd.intersections.size());
553 bd.edges.reserve(3 * bd.intersections.size());
554 bd.node_to_segment.reserve(bd.intersections.size());
558 for (
unsigned int i = 0; i < bd.segments.size(); ++i) {
559 bd.segm_to_node_range.push_back(bd.number_of_nodes());
561 auto& is = bd.segment_to_intersections[i];
563 for (
unsigned int j = 0; j + 1 < is.size(); ++j) {
564 Node left = bd.add_node(i);
565 Node right = bd.add_node(i);
566 bd.add_edge(left, right,
false);
569 bd.segm_to_node_range.push_back(bd.number_of_nodes());
574 static std::vector<Segment> compute_drawing(graph::BloatedDualGraph<Kernel>& bd) {
575 std::vector<Point> node_to_point(bd.number_of_nodes());
576 std::vector<Segment> edge_segments;
578 for (
unsigned int i = 0; i < bd.segments.size(); ++i) {
579 auto left_dir = geometry::normalize(bd.segments[i].to_vector())
580 .perpendicular(CGAL::COUNTERCLOCKWISE);
582 geometry::normalize(bd.segments[i].to_vector()).perpendicular(CGAL::CLOCKWISE);
583 if (i >= bd.segment_to_intersections.size()) {
587 auto& is = bd.segment_to_intersections[i];
588 OGDF_GEOMETRIC_BD_ECHO(bd.segments[i]);
592 Point last = bd.intersections[is[0].intersection_id()];
594 for (
unsigned int j = 0; j + 1 < is.size(); j = j + 1) {
595 Point current = bd.intersections[is[j + 1].intersection_id()];
597 auto mid = last + (current - last) * 0.5;
599 auto left = bd.segm_to_node_range[i] + 2 * j;
600 auto right = bd.segm_to_node_range[i] + 2 * j + 1;
603 CGAL::sqrt(CGAL::to_double(CGAL::squared_distance(current, mid))) / 10, 0.0);
604 node_to_point[left] = mid + left_dir * c;
605 node_to_point[right] = mid + right_dir * c;
610 auto add_segment = [&](
Node u,
Node v) {
612 edge_segments.push_back({node_to_point[u], node_to_point[v]});
616 for (
unsigned int v = 0; v < bd.number_of_nodes(); ++v) {
617 add_segment(v, bd.edges[3 * v]);
618 add_segment(v, bd.edges[3 * v + 1]);
619 add_segment(v, bd.edges[3 * v + 2]);
622 return edge_segments;