Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
LineSegment.h
Go to the documentation of this file.
1
31#pragma once
32
33#ifdef OGDF_INCLUDE_CGAL
34
35# ifndef OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE
36# define OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE false
37# endif
38
44
45# include <iomanip>
46# include <limits>
47# include <variant> // IWYU pragma: keep
48
49# include <CGAL/Segment_2.h>
50# include <boost/variant.hpp> // IWYU pragma: keep
51
52namespace ogdf {
53namespace internal {
54namespace gcm {
55namespace geometry {
56using namespace tools;
57
58template<typename kernel>
59using LineSegment_t = CGAL::Segment_2<kernel>;
60
61/* computes angle between this segment and @ls
62 * @ls line segment
63 * @return angle in [0, \Pi]
64 * */
65template<typename kernel>
66inline typename kernel::FT angle(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
67 OGDF_ASSERT(l1.to_vector().squared_length() > 0);
68 OGDF_ASSERT(l2.to_vector().squared_length() > 0);
69 return geometry::angle(l1.to_vector(), l2.to_vector());
70}
71
72/* compute the full angle between this segment and @ls counterclockwise order
73 * @ls line segment
74 * @return angle in [0, 2 * \Pi]
75 * */
76template<typename kernel>
77inline typename kernel::FT full_angle(const LineSegment_t<kernel>& l1,
78 const LineSegment_t<kernel>& l2) {
79 OGDF_ASSERT(l1.to_vector().squared_length() > 0);
80 OGDF_ASSERT(l2.to_vector().squared_length() > 0);
81 return full_angle(l1.to_vector(), l2.to_vector());
82}
83
84template<typename kernel>
85inline bool turn(const LineSegment_t<kernel>& ls, const Line_t<kernel>& l) {
86 return turn(ls.to_vector(), l.to_vector());
87}
88
89template<typename kernel>
90inline bool left_turn(const LineSegment_t<kernel>& ls, const LineSegment_t<kernel>& l) {
91 return left_turn(ls.to_vector(), l.to_vector());
92}
93
94template<typename kernel>
95inline bool right_turn(const LineSegment_t<kernel>& ls, const LineSegment_t<kernel>& l) {
96 return right_turn(ls.to_vector(), l.to_vector());
97}
98
99template<typename kernel>
100inline bool turn(const LineSegment_t<kernel>& ls, const Point_t<kernel>& p) {
101 return turn(ls.supporting_line(), p);
102}
103
104template<typename kernel>
105inline bool left_turn(const LineSegment_t<kernel>& ls, const Point_t<kernel>& p) {
106 return left_turn(ls.supporting_line(), p);
107}
108
109template<typename kernel>
110inline bool right_turn(const LineSegment_t<kernel>& ls, const Point_t<kernel>& p) {
111 return right_turn(ls.supporting_line(), p);
112}
113
114template<typename kernel>
115inline typename kernel::FT squared_convex_parameter_directed(const LineSegment_t<kernel>& ls,
116 const Point_t<kernel>& p) {
117 OGDF_ASSERT(ls.has_on(p));
118 return (ls.source() - p).squared_length() / ls.to_vector().squared_length();
119}
120
121template<typename kernel>
122inline typename kernel::FT squared_convex_parameter(const LineSegment_t<kernel>& ls,
123 const Point_t<kernel>& point) {
124 OGDF_ASSERT(ls.has_on(point));
125 return std::max(squared_convex_parameter_directed(ls, point),
126 squared_convex_parameter_directed(ls.opposite(), point));
127}
128
129template<typename kernel>
130inline Point_t<kernel> rel_point_at(const LineSegment_t<kernel>& ls, const typename kernel::FT l) {
131 OGDF_ASSERT(0 <= l && l <= 1.0);
132 return ls.source() + (ls.to_vector() * l);
133}
134
135template<typename kernel>
136inline typename kernel::FT value_at(const LineSegment_t<kernel>& ls, const typename kernel::FT x) {
137 if (ls.supporting_line().is_vertical()) {
138 return std::numeric_limits<typename kernel::FT>::infinity();
139 } else {
140 return ls.supporting_line().y_at_x(x);
141 }
142}
143
144template<typename kernel>
145inline typename kernel::FT value_at(const LineSegment_t<kernel>& ls, const Point_t<kernel>& p) {
146 if (ls.supporting_line().is_vertical()) {
147 return p.y();
148 } else {
149 return ls.supporting_line().y_at_x(p.x());
150 }
151}
152
153template<bool closed, typename kernel>
154inline bool is_on(const LineSegment_t<kernel>& ls, const Point_t<kernel>& point) {
155 if (!closed) {
156 return ls.has_on(point) && ls.target() != point;
157 } else {
158 return ls.has_on(point);
159 }
160}
161
162template<typename kernel>
163inline bool is_on(const LineSegment_t<kernel>& ls, const Point_t<kernel>& point) {
164 return is_on<false>(ls, point);
165}
166
167template<typename kernel>
168inline bool overlapping(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
169 const bool parallel = CGAL::parallel(l1.supporting_line(), l2.supporting_line());
170 const bool on_l1 = is_on<true>(l1, l2.source()) || is_on<true>(l1, l2.target());
171 const bool on_l2 = is_on<true>(l2, l1.source()) || is_on<true>(l2, l1.target());
172 return (on_l1 || on_l2) && parallel;
173}
174
175template<typename kernel>
176inline bool overlapping(const LineSegment_t<kernel>& ls, const Line_t<kernel>& line) {
177 const bool parallel = parallel(ls.supporting_line(), line);
178 // if both segments are parallel, then it would be sufficient to check wheather base or end is on the line
179 // to be a little more robust, check if one of both is on the line. therefore small error are overseen
180 const bool on_line = line.has_on(ls.source()) || line.has_on(ls.target());
181 return on_line && parallel;
182}
183
184template<typename kernel>
185inline bool do_intersect_wo_targets(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
186 return CGAL::do_intersect(l1, l2) && !l1.has_on(l2.target()) && !l2.has_on(l1.target());
187}
188
189template<typename kernel>
190inline bool do_intersect_open(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
191 return CGAL::do_intersect(l1, l2) && !l1.has_on(l2.target()) && !l2.has_on(l1.target())
192 && !l1.has_on(l2.source()) && !l2.has_on(l1.source());
193}
194
195template<typename kernel>
196inline bool do_intersect_wo_target(const LineSegment_t<kernel>& l1, const Line_t<kernel>& l) {
197 return CGAL::do_intersect(l1, l) && !l.has_on(l1.target());
198}
199
200template<typename kernel>
201inline bool do_intersect_wo_target(const Line_t<kernel>& l, const LineSegment_t<kernel>& l1) {
202 return geometry::do_intersect_wo_target(l1, l);
203}
204
205template<typename kernel>
206inline bool do_intersect_wo_target(const LineSegment_t<kernel>& l1, const Ray_t<kernel>& r) {
207 return CGAL::do_intersect(l1, r) && !r.has_on(l1.target());
208}
209
210template<typename kernel>
211inline bool do_intersect_wo_target(const Ray_t<kernel>& r, const LineSegment_t<kernel>& l1) {
212 return geometry::do_intersect_wo_target(l1, r);
213}
214
215template<typename kernel>
216inline bool have_common_endpoints(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
217 return l1.source() == l2.source() || l1.source() == l2.target() || l1.target() == l1.source()
218 || l1.target() == l2.target();
219}
220
221template<typename kernel>
222inline Point_t<kernel> get_common_endpoint(const LineSegment_t<kernel>& l1,
223 const LineSegment_t<kernel>& l2) {
224 OGDF_ASSERT(have_common_endpoints(l1, l2));
225
226 if (l1.source() == l2.source() || l1.source() == l2.target()) {
227 return l1.source();
228 } else {
229 return l1.target();
230 }
231}
232
233template<class T, class Variant>
234auto get_if(Variant* v) -> decltype(std::get_if<T>(v)) {
235 return std::get_if<T>(v);
236}
237
238template<class T, class Variant>
239auto get_if(Variant* v) -> decltype(boost::get<T>(v)) {
240 return boost::get<T>(v);
241}
242
243template<typename kernel>
244inline Point_t<kernel> intersect(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
245 OGDF_ASSERT(!l1.is_degenerate());
246 OGDF_ASSERT(!l2.is_degenerate());
247
248 auto result = CGAL::intersection(l1, l2);
249 if (!result) {
250 return Point_t<kernel>(std::numeric_limits<double>::max(),
251 std::numeric_limits<double>::max());
252 }
253
254 Point_t<kernel> intersection;
255 if (auto s = get_if<LineSegment_t<kernel>>(&*result)) {
256 intersection = s->source();
257 } else if (auto p = get_if<Point_t<kernel>>(&*result)) {
258 intersection = *p;
259 }
260 //TODO
261 //OGDF_ASSERT(is_on<true>(l1, intersection));
262 //OGDF_ASSERT(is_on<true>(l2, intersection));
263 return intersection;
264}
265
266template<typename kernel>
267inline Point_t<kernel> intersect(const LineSegment_t<kernel>& l1, const Line_t<kernel>& l2) {
268 OGDF_ASSERT(!l1.is_degenerate());
269 OGDF_ASSERT(!l2.is_degenerate());
270 auto result = CGAL::intersection(l1, l2);
271 if (!result) {
272 return Point_t<kernel>(std::numeric_limits<unsigned int>::max(),
273 std::numeric_limits<unsigned int>::max());
274 }
275
276 Point_t<kernel> intersection;
277 if (auto s = get_if<LineSegment_t<kernel>>(&*result)) {
278 intersection = s->source();
279 } else if (auto p = get_if<Point_t<kernel>>(&*result)) {
280 intersection = *p;
281 }
282 OGDF_ASSERT(is_on<true>(l1, intersection));
283 OGDF_ASSERT(l2.has_on(intersection));
284 return intersection;
285}
286
287template<typename kernel>
288inline Point_t<kernel> intersect(const Line_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
289 return intersect(l2, l1);
290}
291
292template<typename kernel>
293inline Point_t<kernel> intersect(const LineSegment_t<kernel>& l1, const Ray_t<kernel>& r) {
294 OGDF_ASSERT(!l1.is_degenerate());
295 OGDF_ASSERT(!r.is_degenerate());
296
297 auto result = CGAL::intersection(l1, r);
298 if (!result) {
299 return Point_t<kernel>(std::numeric_limits<unsigned int>::max(),
300 std::numeric_limits<unsigned int>::max());
301 }
302
303
304 Point_t<kernel> intersection;
305 if (auto s = get_if<LineSegment_t<kernel>>(&*result)) {
306 intersection = s->source();
307 } else if (auto p = get_if<Point_t<kernel>>(&*result)) {
308 intersection = *p;
309 }
310 OGDF_ASSERT(OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE || is_on<true>(l1, intersection));
311 OGDF_ASSERT(OGDF_GEOMETRIC_INEXACT_NUMBER_TYPE || r.has_on(intersection));
312 return intersection;
313}
314
315template<typename kernel>
316inline Point_t<kernel> intersect(const Ray_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
317 return intersect(l2, l1);
318}
319
320template<typename kernel>
321inline typename kernel::FT order_along_seg(const LineSegment_t<kernel>& reference
322
323 ,
324 const LineSegment_t<kernel>& l_1, const LineSegment_t<kernel>& l_2) {
325 auto cross = [&](const Vector_t<kernel>& v_1, const Vector_t<kernel>& v_2) {
326 return v_1.x() * v_2.y() - v_1.y() * v_2.x();
327 };
328
329 auto s = reference.target() - reference.source();
330 auto r_1 = l_1.target() - l_1.source();
331 auto r_2 = l_2.target() - l_2.source();
332
333 auto c_1 = cross(reference.source() - l_1.source(), s);
334 auto c_2 = cross(reference.source() - l_2.source(), s);
335
336 auto d_1 = cross(r_1, s);
337 auto d_2 = cross(r_2, s);
338
339 return c_1 * d_2 - c_2 * d_1;
340}
341
342template<typename kernel>
343void serialize(const LineSegment_t<kernel>& ls, std::ostream& os) {
344 serialize(ls.source(), os);
345 serialize(ls.target(), os);
346}
347
348template<typename kernel>
349inline bool operator<(const LineSegment_t<kernel>& l1, const LineSegment_t<kernel>& l2) {
350 return l1.source() < l2.source() || (l1.source() == l2.source() && l1.target() < l2.target());
351}
352
353template<typename Kernel, typename T>
354LineSegment_t<Kernel> cast(const LineSegment_t<T>& segment) {
355 return {cast<Kernel>(segment.source()), cast<Kernel>(segment.target())};
356}
357
358} //namespace
359}
360}
361}
362
363#endif
void intersection(Graph &G1, const Graph &G2, const NodeArray< node > &nodeMap, bool directed=false)
Computes the intersection of G1 and G2.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
bool operator<(const MDMFLengthAttribute &x, const MDMFLengthAttribute &y)
The namespace for all OGDF objects.