Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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