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