33 #ifdef OGDF_INCLUDE_CGAL
46 # include <CGAL/Min_circle_2.h>
47 # include <CGAL/Min_circle_2_traits_2.h>
54 template<
typename Kernel,
typename Graph>
55 class CrossingMinimalRegion {
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>;
62 using Node =
typename Graph::Node;
63 using Edge =
typename Graph::Edge;
65 using BD = BloatedDualGraph<Kernel>;
67 static Segment get_segment(
const Drawing& d,
const Node& w,
const Node& u,
68 const geometry::Rectangle_t<Kernel>& rect) {
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());
74 geometry::Ray_t<Kernel>
r(d.get_point(u), geometry::Vector_t<Kernel>(delta_x, delta_y));
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))));
80 Segment s = {d.get_point(u), d.get_point(u) + geometry::normalize(
r.to_vector()) * t * 1.1};
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
89 const auto& g = d.get_graph();
91 bd.segments.reserve(g.number_of_nodes() * v->degree() + edges.size());
92 std::vector<int> left_to_right_cost;
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()};
103 bd.segments.push_back(s);
104 nodes.insert(e->target());
105 nodes.insert(e->source());
106 sampled_edges.insert(e);
108 left_to_right_cost.push_back(0);
109 for (
auto w : neighbors) {
110 if (e->isIncident(w)) {
113 if (geometry::left_turn(s, d.get_point(w))) {
114 left_to_right_cost.back()++;
116 left_to_right_cost.back()--;
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()};
128 bd.segments.push_back(s);
130 left_to_right_cost.push_back(0);
131 for (
auto e : g.edges(u)) {
132 if (sampled_edges.find(e) == sampled_edges.end()) {
135 auto x = e->opposite(u);
136 if (e->isIncident(w) || e->isIncident(v)) {
139 if (geometry::left_turn(s, d.get_point(x))) {
140 left_to_right_cost.back()--;
142 left_to_right_cost.back()++;
148 std::vector<Point> p_rect;
149 for (
unsigned int i = 0; i < 4; ++i) {
153 p_rect.push_back(rect_box.vertex(i) + geometry::Vector_t<Kernel>(x, y));
156 for (
unsigned int i = 0; i < 4; ++i) {
157 Segment s(p_rect[i], p_rect[(i + 1) % 4]);
159 if (s.target() < s.source()) {
160 s = {s.target(), s.source()};
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());
169 left_to_right_cost.push_back(
170 -d.get_graph().number_of_edges() * d.get_graph().number_of_edges());
174 return left_to_right_cost;
177 static bool check_segments(std::vector<Segment>& segments) {
179 auto f_check_point = [&](
const Segment& s,
const Point& p) {
180 if (s.has_on(p) && s.source() != p && s.target() != p) {
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;
194 if (!f_check_point(segments[i], segments[j].target())) {
195 Logger::slout() <<
"[math] " << i <<
" " << j <<
"; " << segments[i] <<
" "
196 << segments[j] << std::endl;
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()
210 auto rep = geometry::find_representative_node(bd, p);
212 typename BD::Node min_vertex = rep;
213 double min_weight = 0;
215 std::vector<typename BD::Node> parent(bd.number_of_nodes());
216 std::vector<typename BD::Edge> parent_edge(bd.number_of_nodes());
218 auto f_weight = [&](
typename BD::Node v,
typename BD::Edge e) {
219 if (bd.is_face_edge(e) || bd.degree(v) == 2) {
221 }
else if (bd.is_left(v)) {
222 return left_to_right_cost[bd.node_to_segment[v]];
224 return -left_to_right_cost[bd.node_to_segment[v]];
228 auto expand = [&](
typename BD::Node w,
typename BD::Edge e) {
229 bool bad_edge = w >= min_node && bd.edges[e] >= min_node;
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);
239 queue.push_back(rep);
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);
255 while (!queue.empty()) {
256 typename BD::Node current = queue.back();
258 if (weight[current] < min_weight) {
259 min_vertex = current;
260 min_weight = weight[current];
264 handle_edge(current, 3 * current);
265 handle_edge(current, 3 * current + 1);
266 handle_edge(current, 3 * current + 2);
273 std::vector<int> left_to_right_cost;
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) {
279 left_to_right_cost.clear();
281 left_to_right_cost = generate_segments(d, v, neighbors, edges, bd, rect_box);
284 # ifdef OGDF_GEOMETRIC_CR_MIN_DEBUG
285 std::cout <<
"intersect..." << std::flush;
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;
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;
298 static geometry::BloatedDual<Kernel> bdc;
300 # ifdef OGDF_GEOMETRIC_CR_MIN_DEBUG
301 std::cout <<
"done" << std::endl;
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);
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);