Test if two segments are roughly collinear (on the same line)
The problem with your approach is that the cross product value depends on the measurement scale.
Maybe the most intuitive measure of collinearity is the angle between the line segments. Let's calculate it:
import math
def slope(line):
"""Line slope given two points"""
p1, p2 = line
return (p2[1] - p1[1]) / (p2[0] - p1[0])
def angle(s1, s2):
"""Angle between two lines given their slopes"""
return math.degrees(math.atan((s2 - s1) / (1 + (s2 * s1))))
ang = angle(slope(b), slope(a))
print('Angle in degrees = ', ang)
Angle in degrees = 2.2845
I made use of an answer by Anderson Oliveira.
The cross-product of two vector a
and b
can be defined defined as: ||a|| ||b|| sin(θ)
where θ
is the angle between the two vectors. The thing is the even if θ
is small, the product of the two norms can be huge and can result in a big cross-product. This is your case:
na = np.linalg.norm(a, axis=1) # array([9824940.10284589, 9824924.42969893])
nb = np.linalg.norm(b, axis=1) # array([9824909.95439353, 9824863.32407282])
nprod = na * nb # array([9.65291518e+13, 9.65285397e+13])
sinθ = crossproduct / nprod # array([7.69491364e-06, 1.71301508e-05])
Indeed, sinθ
is very small. This means θ
is very small too (in fact, θ
is roughly equal to sinθ
value since the derivative of sin(θ)
with θ = 1
is 1).
How can I determine if the segments are colinear with the crossproduct result?
You can compute the value np.abs(sinθ)
base on the above code, set an arbitrary threshold and check if the value is smaller than the chosen threshold. The best value for the threshold depends of your actual application/input (eg. statistical noise, precision of the input, accuracy of the computations, etc.). If you do not know what to use, you can start with 1e-4
for example.
Is there a possibility of using a tolerance in meters to tell if the segments are roughly collinear?
Note that assuming the input vectors are in meters, then the value of the cross-product is in square meters based on the above formula. Thus, a tolerance in meters does not make much sense. More generally, an setting an absolute tolerance is certainly a bad idea. The above solution works using a tolerance relative to the input vectors.