Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
intersection.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
12#include <sparse/general.h>
13#include <math.h>
14
15static double cross(double *u, double *v){
16 return u[0]*v[1] - u[1]*v[0];
17}
18
19
20/*
21
22There's a nice approach to this problem that uses vector cross
23products. Define the 2-dimensional vector cross product v * w to be
24vxwy \[Minus] vywx (this is the magnitude of the 3-dimensional cross
25product).
26
27Suppose the two line segments run from p to p + r and from q to q +s.
28Then any point on the first line is representable as p + t r (for a
29scalar parameter t) and any point on the second line as q + u s (for a
30scalar parameter u).
31
32The two lines intersect if we can find t and u such that:
33
34p + t r = q + u s
35
36cross both sides with s, getting
37
38(p + t r) * s = (q + u s) * s
39
40And since s * s = 0, this means
41
42t(r * s) = (q \[Minus] p) * s
43
44And therefore, solving for t:
45
46t = (q \[Minus] p) * s / (r * s)
47
48In the same way, we can solve for u:
49
50u = (q \[Minus] p) * r / (r * s)
51
52Now if r * s = 0 then the two lines are parallel.
53(There are two cases: if (q \[Minus] p) * r = 0 too,
54then the lines are collinear, otherwise they never intersect.)
55
56Otherwise the intersection point is on the original pair
57of line segments if 0 <= t <= 1 and 0 <= u <= 1.
58
59*/
60
61static double dist(int dim, double *x, double *y){
62 int k;
63 double d = 0;
64 for (k = 0; k < dim; k++) d += (x[k] - y[k])*(x[k]-y[k]);
65 return sqrt(d);
66}
67
68static double point_line_distance(double *p, double *q, double *r){
69 /* distance between point p and line q--r */
70 enum {dim = 2};
71 double t = 0, b = 0;
72 int i;
73 double tmp;
74
75 /* t = ((p - q).(r - q))/((r - q).(r - q)) gives the position of the project of p on line r--q */
76 for (i = 0; i < dim; i++){
77 t += (p[i] - q[i])*(r[i] - q[i]);
78 b += (r[i] - q[i])*(r[i] - q[i]);
79 }
80 if (b <= MACHINEACC) return dist(dim, p, q);
81 t = t/b;
82
83 /* pointLine = Norm[p - (q + t (r - q))];
84 If [t >= 0 && t <= 1, pointLine, Min[{Norm[p - q], Norm[p - r]}]]];
85 */
86
87 if (t >= 0 && t <= 1){
88 b = 0;
89 for (i = 0; i < dim; i++){
90 tmp = p[i] - (q[i] + t*(r[i] - q[i]));
91 b += tmp*tmp;
92 }
93 return sqrt(b);
94 }
95 t = dist(dim, p, q);
96 b = dist(dim, p, r);
97 return MIN(t, b);
98
99}
100
101static double line_segments_distance(double *p1, double *p2, double *q1, double *q2){
102 /* distance between line segments p1--p2 and q1--q2 */
103 double t1, t2, t3, t4;
104 t1 = point_line_distance(p1, q1, q2);
105 t2 = point_line_distance(p2, q1, q2);
106 t3 = point_line_distance(q1, p1, p2);
107 t4 = point_line_distance(q2, p1, p2);
108 t1 = MIN(t1,t2);
109 t3 = MIN(t3,t4);
110 return MIN(t1, t3);
111}
112
113
114double intersection_angle(double *p1, double *p2, double *q1, double *q2){
115
116 /* give two lines p1--p2 and q1--q2, find their intersection agle
117 and return Abs[Cos[theta]] of that angle.
118 - If the two lines are very close, treat as if they intersect.
119 - If they do not intersect or being very close, return -2.
120 - If the return value is close to 1, the two lines intersects and is close to an angle of 0 o Pi;
121 . lines that intersect at close to 90 degree give return value close to 0
122 - in the special case of two lines sharing an end point, we return Cos[theta], instead of
123 . the absolute value, where theta
124 . is the angle of the two rays emitting from the shared end point, thus the value can be
125 . from -1 to 1.
126 */
127 enum {dim = 2};
128 double r[dim], s[dim], qp[dim];
129 double rnorm = 0, snorm = 0, b, t, u;
130 // double epsilon = sqrt(MACHINEACC), close = 0.01;
131 //this may be better. Apply to ngk10_4 and look at double edge between 28 and 43. double epsilon = sin(10/180.), close = 0.1;
132 double epsilon = sin(1/180.), close = 0.01;
133 int line_dist_close;
134 int i;
135 double res;
136
137 for (i = 0; i < dim; i++) {
138 r[i] = p2[i] - p1[i];
139 rnorm += r[i]*r[i];
140 }
141 rnorm = sqrt(rnorm);
142
143 for (i = 0; i < dim; i++) {
144 s[i] = q2[i] - q1[i];
145 snorm += s[i]*s[i];
146 }
147 snorm = sqrt(snorm);
148 b = cross(r, s);
149 line_dist_close = (line_segments_distance(p1, p2, q1, q2) <= close*MAX(rnorm, snorm));
150 if (fabs(b) <= epsilon*snorm*rnorm){/* parallel */
151 if (line_dist_close) {/* two parallel lines that are close */
152 return 1;
153 }
154 return -2;/* parallel but not close */
155 }
156 for (i = 0; i < dim; i++) qp[i] = q1[i] - p1[i];
157 t = cross(qp, s)/b;
158 u = cross(qp, r)/b;
159 if ((t >= 0 && t <= 1 && u >= 0 && u <= 1) /* they intersect */
160 || line_dist_close){/* or lines are close */
161 double rs = 0;
162 if (rnorm*snorm < MACHINEACC) return 0;
163 for (i = 0; i < dim; i++){
164 rs += r[i]*s[i];
165 }
166 res = rs/(rnorm*snorm);
167 /* if the two lines share an end point */
168 if (p1[0] == q1[0] && p1[1] == q1[1]){
169 return res;
170 } else if (p1[0] == q2[0] && p1[1] == q2[1]){
171 return -res;
172 } else if (p2[0] == q1[0] && p2[1] == q1[1]){
173 return -res;
174 } else if (p2[0] == q2[0] && p2[1] == q2[1]){
175 return res;
176 }
177
178 /* normal case of intersect or very close */
179 return fabs(res);
180 }
181 return -2;/* no intersection, and lines are not even close */
182}
183
#define MIN(a, b)
Definition arith.h:28
#define MACHINEACC
Definition general.h:80
static double dist(int dim, double *x, double *y)
static double point_line_distance(double *p, double *q, double *r)
static double cross(double *u, double *v)
static double line_segments_distance(double *p1, double *p2, double *q1, double *q2)
double intersection_angle(double *p1, double *p2, double *q1, double *q2)
Definition grammar.c:93
#define MAX(a, b)
Definition write.c:31