2D Line Mathematics Using Homogeneous Coordinates

Introduction

It is possible to compute the intersection of two lines and the line given two points using cross-product.

In this blog post, I would like to quickly derive how to do so using homogeneous coordinate representations.

2D Point Representations

Inhomogeneous Coordinates

The inhomogeneous coordinates for a 2D point are just ordinary two-value Cartesian coordinates.

x=(x,y)

Augmented Coordinates

The augmented coordinates for a 2D point are just the 2D inhomogeneous coordinates with an additional constant 1.

x¯=(x,y,1)

Homogeneous Coordinates

The homogeneous coordinates are just the augmented coordinates scaled by some value w~.

x~=w~x¯=w~(x,y,1)=(w~x,w~y,w~)=(x~,y~,w~)

where w~R.

When w~=0, x~ is called ideal point and do not have the corresponding inhomogeneous coordinates.

Intersection

The 2D line l:ax+by+c=0 could be represented using homogeneous coordinates, l~=(a,b,c). It can also be normalized so that l=(n^x,n^y,d)=(n,d) with n=1.

Suppose x=(x,y) is the intersection of two lines l~1=(a1,b1,c1) and l~2=(a2,b2,c2), we must have

x¯l~1=0x¯l~2=0

Because the cross product of l~1 and l~2, l~1×l~2, is perpendicular to both l~1 and l~2, i.e.,

(l~1×l~2)l~1=0(l~1×l~2)l~2=0

We must have

l~1×l~2=w~x¯=(w~x,w~y,w~)

for some w~R.

Therefore,

x¯==1w~l~1×l~2=1w~(w~x,w~y,w~)

line_intersection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from typing import Tuple, Optional
import numpy as np


def get_2d_line_intersection(
line_1: Tuple[float, float, float],
line_2: Tuple[float, float, float]) -> Optional[Tuple[float, float]]:
"""Get the 2D line intersection.

Args:
line_1 (Tuple[float, float, float]): Homogenous coordinate representation of a 2D line.
line_2 (Tuple[float, float, float]): Homogenous coordinate representation of a 2D line.

Returns:
Tuple[float, float]: Inhomogeneous coordinate representation of the intersection.
"""

x_homo = np.cross(line_1, line_2)
if x_homo[2] == 0:
return None
x = x_homo / x_homo[2]

return (x[0], x[1])


def verify_2d_line_intersection(line_1: Tuple[float, float, float],
line_2: Tuple[float, float, float],
intersection: Tuple[float, float]) -> bool:

status = np.isclose(
line_1[0] * intersection[0] + line_1[1] * intersection[1] + line_1[2],
0) and np.isclose(
line_2[0] * intersection[0] + line_2[1] * intersection[1] +
line_2[2], 0)

return status


if __name__ == "__main__":

np.random.seed(0)

line_1 = np.random.rand(3)
line_2 = np.random.rand(3)

intersection = get_2d_line_intersection(line_1=line_1, line_2=line_2)
print(intersection)
if intersection is not None:
status = verify_2d_line_intersection(line_1=line_1,
line_2=line_2,
intersection=intersection)
assert status == True

2D Line from 2D Points

Suppose the line l~=(a,b,c) passes two points x1=(x1,y1) and x2=(x2,y2), similar to the intersection calculation, we must have

x¯1l~=0x¯2l~=0

Because the cross product of x¯1 and x¯2, x¯1×x¯2, is perpendicular to both x¯1 and x¯2, i.e.,

x¯1(x¯1×x¯2)=0x¯2(x¯1×x¯2)=0

We must have

x¯1×x¯2=v~l¯=l~

If the two points were represented using homogeneous coordinates, equivalently,

x~1×x~2=l~

line_representation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from typing import Tuple, Optional
import numpy as np


def get_2d_line(
point_1: Tuple[float, float],
point_2: Tuple[float, float]) -> Optional[Tuple[float, float, float]]:
"""Get the 2D line.

Args:
point_1 (Tuple[float, float, float]): Inhomogeneous coordinate representation of a 2D point.
point_2 (Tuple[float, float, float]): Inhomogeneous coordinate representation of a 2D point.

Returns:
Tuple[float, float]: Homogeneous coordinate representation of the 2D line.
"""

point_1_homo = (point_1[0], point_1[1], 1)
point_2_homo = (point_2[0], point_2[1], 1)
if point_1_homo == point_2_homo:
return None
line = np.cross(point_1_homo, point_2_homo)

return (line[0], line[1], line[2])


def verify_2d_line_point(line: Tuple[float, float, float],
point: Tuple[float, float]) -> bool:

status = np.isclose(line[0] * point[0] + line[1] * point[1] + line[2], 0)

return status


if __name__ == "__main__":

np.random.seed(0)

point_1 = np.random.rand(2)
point_2 = np.random.rand(2)

line = get_2d_line(point_1=point_1, point_2=point_2)
print(line)
if line is not None:
status = verify_2d_line_point(line=line, point=point_1)
assert status == True
status = verify_2d_line_point(line=line, point=point_2)
assert status == True

References

Author

Lei Mao

Posted on

11-01-2021

Updated on

11-01-2021

Licensed under


Comments