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
PlanarSubdivision.h
Go to the documentation of this file.
1
31#pragma once
32
33#ifdef OGDF_INCLUDE_CGAL
34
41
42# include <CGAL/Exact_predicates_exact_constructions_kernel.h>
43
44# ifndef OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE
45# define OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE false
46# endif
47
48namespace ogdf {
49namespace internal {
50namespace gcm {
51namespace geometry {
52
53
54struct Intersection {
55 Intersection(unsigned int _seg_a, unsigned int _seg_b) : seg_a(_seg_a), seg_b(_seg_b) {
56 //nothing to
57 }
58
59 unsigned int seg_a = -1; // first segment id
60 unsigned int seg_b = -1; // second segment id
61 unsigned int pos_on_a = -1; // ordered position on segment a
62 unsigned int pos_on_b = -1; // ordered position on segment b
63 bool proper = true; // is a proper intersection , i.e.,
64 // intersection point is an interior point of both segments;
65 bool is_source = false;
66 bool is_target = false;
67
68 bool is_incident(const unsigned int segment) const {
69 return seg_a == segment || seg_b == segment;
70 }
71
72 unsigned int opposite(const unsigned int segment) const {
73 if (seg_a == segment) {
74 return seg_b;
75 } else {
76 return seg_a;
77 }
78 }
79
80 unsigned int pos(const unsigned int segment) const {
81 if (seg_a == segment) {
82 return pos_on_a;
83 } else {
84 return pos_on_b;
85 }
86 }
87};
88
91template<typename Kernel, bool OPEN = true>
93private:
94 using LineSegment = geometry::LineSegment_t<Kernel>;
95 using Point = geometry::Point_t<Kernel>;
96 using Polygon = geometry::Polygon_t<Kernel>;
97 using Line = geometry::Line_t<Kernel>;
98 using Ray = geometry::Ray_t<Kernel>;
99 using Direction = geometry::Direction_t<Kernel>;
100
101 using ExactKernel = CGAL::Exact_predicates_exact_constructions_kernel;
102 using ExactLineSegment = geometry::LineSegment_t<ExactKernel>;
103 using ExactPoint = geometry::Point_t<ExactKernel>;
104
105
106 enum class EventType { Start, End };
107
108 struct Event {
109 Point p;
110 unsigned int segment_id;
112
113 Event(Point _p, unsigned int _id, EventType _ev) : p(_p), segment_id(_id), event(_ev) {
114 //nothing to do
115 }
116 };
117
118
119public:
120 using LCGEdge = std::tuple<unsigned int, unsigned int, unsigned int>;
121
126 template<typename IntersectionEvent>
127 void sweep(std::vector<LineSegment>& segments, IntersectionEvent&& intersection_event) {
128 std::vector<unsigned int> segment_to_active(segments.size(), -1);
129 std::vector<unsigned int> active;
130
131 auto add_to_active = [&](unsigned int segment_id) {
132 segment_to_active[segment_id] = active.size();
133 active.push_back(segment_id);
134 };
135
136 auto remove_from_active = [&](unsigned int segment_id) {
137 unsigned int active_id = segment_to_active[segment_id];
138 std::swap(active[active_id], active.back());
140 active.pop_back();
142 };
143 std::vector<Event> events;
144 events.reserve(2 * segments.size());
145
146
147 for (unsigned int i = 0; i < segments.size(); ++i) {
148 Event ev_start(std::min(segments[i].source(), segments[i].target()), i, EventType::Start);
149 Event ev_end(std::max(segments[i].source(), segments[i].target()), i, EventType::End);
150
151 events.push_back(ev_start);
152 events.push_back(ev_end);
153 }
154
155
156 std::sort(events.begin(), events.end(), [&](const Event& a, const Event& b) -> bool {
157 return a.p < b.p || (a.p == b.p && a.event == EventType::Start);
158 });
159
160
161 for (const Event& e : events) {
162 auto& new_segment = segments[e.segment_id];
163 if (e.event == EventType::Start) {
164 for (unsigned int active_id : active) {
167
168 if (OPEN && geometry::do_intersect_open(new_segment, active_segment)) {
169 intersection_event(e.segment_id, active_id);
170 }
171
172 if (!OPEN && CGAL::do_intersect(new_segment, active_segment)) {
173 intersection_event(e.segment_id, active_id);
174 }
175 }
176 add_to_active(e.segment_id);
177 } else {
178 remove_from_active(e.segment_id);
179 }
180 }
181 }
182
183 //robustness depends on kernel
184 void subdivision(std::vector<LineSegment>& segment,
185 std::vector<Point>& intersections // node_to_point
186 ,
187 std::vector<LCGEdge>& edge_list) {
188 //compute intersections
189 std::vector<std::vector<unsigned int>> intersections_of_segment(segment.size());
190
191 //TODO handle start and end points;
192
193 auto intersection_event = [&](unsigned int seg_1, unsigned int seg_2) {
194 //TODO handle collinearity?
195
196 unsigned int v = intersections.size();
197
198 intersections_of_segment[seg_1].push_back(v);
199 intersections_of_segment[seg_2].push_back(v);
200
201 Point is = geometry::intersect(segment[seg_1], segment[seg_2]);
202 intersections.push_back(is);
203
204 OGDF_ASSERT(CGAL::squared_distance(segment[seg_1], is) < 1);
205 OGDF_ASSERT(CGAL::squared_distance(segment[seg_2], is) < 1);
206
209 };
210
211 for (unsigned int i = 0; i < segment.size(); ++i) {
212 auto& s = segment[i];
213 intersections_of_segment[i].push_back(intersections.size());
214 intersections.push_back(s.source());
215 intersections_of_segment[i].push_back(intersections.size());
216 intersections.push_back(s.target());
217 }
218 sweep(segment, intersection_event);
219
220 //identify and remove duplication of intersections
221
222 datastructure::UnionFind node_mapping(intersections.size());
223 node_mapping.all_to_singletons();
224
225 std::vector<unsigned int> same(intersections.size(), 0);
226 for (unsigned int i = 0; i < same.size(); ++i) {
227 same[i] = i;
228 }
229
230 std::sort(same.begin(), same.end(),
231 [&](unsigned int a, unsigned int b) { return intersections[a] < intersections[b]; });
232
233 for (unsigned int i = 0; i + 1 < same.size(); ++i) {
234 unsigned int u = same[i];
235 unsigned int v = same[i + 1];
236 if (intersections[u] == intersections[v]) {
237 node_mapping.merge(u, v);
238 }
239 }
240
241 // build planar arrangement
242 for (unsigned int i = 0; i < segment.size(); ++i) {
243 auto& is = intersections_of_segment[i];
244 //intersections += is.size();
245 std::sort(is.begin(), is.end(), [&](const unsigned int a, unsigned int b) {
246 const Point& p_a = intersections[a];
247 const Point& p_b = intersections[b];
248
249 auto d_a = CGAL::squared_distance(segment[i].source(), p_a);
250 auto d_b = CGAL::squared_distance(segment[i].source(),
251 p_b); //order a long line with respect to source
252 return d_a < d_b;
253 });
254 for (unsigned int j = 0; j + 1 < is.size(); ++j) {
255 unsigned int u = node_mapping[is[j]];
256 unsigned int v = node_mapping[is[j + 1]];
257
258 if (u != v) {
260 || segment[i].has_on(intersections[u]));
262 || segment[i].has_on(intersections[v]));
263
264 edge_list.push_back(LCGEdge(u, v, i));
265 }
266 }
267 }
268 }
269
270 std::vector<Intersection> subdivision(std::vector<LineSegment>& segment) {
271 //compute intersections
272 std::vector<Intersection> intersecting_segments;
273 //TODO handle start and end points;
274
275 auto intersection_event = [&](unsigned int seg_1, unsigned int seg_2) {
276 intersecting_segments.push_back({seg_1, seg_2});
277 };
278
279 sweep(segment, intersection_event);
281 }
282};
283
284
285}
286}
287}
288}
289
290#endif
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:41
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.
Direction
Definition basic.h:134