Question

I need to find the 'inner' angle in degrees between two segments (lines), the less than 180 degrees that is. Any fast way to do it in python2.7? (Shapely doesnt seem to have a function for this)

segment1 is x1,y1,x2,y2

segment2 is x3,y3,x4,y4

enter image description here

Was it helpful?

Solution

I originally suggested using the law of cosines in vector form: if your two line segments are given by the vectors b and c, and the angle between them is θ, then

b · c = |b| |c| cos θ

and so

θ = cos−1((b · c) / |b| |c|)

But as Alex Wien points out in comments, this gives poor results when θ is close to zero:

>>> theta = 1e-6
>>> a = Vector(1, 0)
>>> b = Vector(cos(theta), sin(theta))
>>> acos(a.dot(b) / (a.length * b.length))
9.999334257726859e-07
>>> abs(theta - _) / theta
6.657422731408927e-05

which is a relative error of getting on for one part in ten thousand. For very small angles you can get 100% relative error:

>>> theta = 1e-9
>>> a = Vector(1, 0)
>>> b = Vector(cos(theta), sin(theta))
>>> acos(a.dot(b) / (a.length * b.length))
0.0

An alternative formula uses the arc tangent instead of the arc cosine:

θ = tan−1(|a × b| / (a · b))

and this gives a more accurate result for small angles:

>>> atan2(abs(a.cross(b)), a.dot(b))
1e-09
>>> theta == _
True

(The alternative formula follows from the property of the cross product that |a × b| = |a| |b| sin θ. Divide this by the law of cosines to get the result used here.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top