点与点之间, 线与线之间,点与线之间的位置关系是一类非常重要的问题。它不仅是平面几何学的基石,也常常应用于LBS(Location Based Service),社交网络,以及数据库查询等领域。
本文中,我将给出判断这些关系的相关算法,作为参考。需要说明的是,我给出的这些问题的解法,都是建立在二维平面空间之上。有关多维空间的位置关系,大家可以仿照二维空间中问题的思路,做相应的拓展。
语言上,我用的当然还是Python.
点与点之间的距离
先从最简单的点与点的位置关系说起。一般情况下,我们只关心点与点之间的距离。
1. 点类的定义
为使算法思路更加清晰,先定义点类 Point
,既然是在二维空间上,那么每个点都应该有两个属性:x, y分别代表点的横纵坐标。
class Point(object):
"""Point are two-dimension"""
def __init__(self, x, y):
self.x = x
self.y = y
接下来就看看如何计算两点之间距离:当然可以用初中学的欧氏距离最基本的计算方法。但是考虑到代码编写的效率,以及方便以后向高维空间拓展。我在本文中将尽量使用向量计算。
而为了简化代码,我们使用对于向量运算已经相当成熟的库numpy
2. 两点之间距离的计算
显然,两点可以构成向量,而向量的长度则是其内积的开方。空间中,点 A 与点
为了和本文之后的问题保持编码风格上一致,同时简化代码编写。我使用对向量运算已经极为成熟的库numpy帮助计算。并且定义了一个新的类 Vector
,类 Vector
以向量的起点和终点作为输入,生成一个只拥有属性x和y的向量对象。
最后,和前面定义的类放在一起,代码如下:
import numpy as np
# numpy help us do some vector calculation
class Point(object):
"""Point are two-dimension"""
def __init__(self, x, y):
self.x = x
self.y = y
class Vector(object):
"""start and end are two points"""
def __init__(self, start, end):
self.x = end.x - start.x
self.y = end.y - start.y
def pointDistance(p1, p2):
"""calculate the distance between point p1 and p2"""
# v: a Vector object
v = Vector(p1, p2)
# translate v to a ndarray object
t = np.array([v.x, v.y])
# calculate the inner product of ndarray t
return float(np.sqrt(t @ t))
说明一下,在Python3.5以后的版本中,使用numpy库时,ndarray对象之间的乘法可以用 @
,代替之前的 v1.dot(v2)
这样的形式。
点与线之间的位置关系
1. 线的分类
点与线之间的位置关系就要稍微复杂一些了,复杂之处在于线分线段和直线两种情况。但是,在定义类的时候我都用两点来代表线段(直线)的两个属性。于是,至少代码看上去是没什么分别的。
不同之处在于,线段的两个点事两个端点,而直线的两个点是直线上任意两点。
class Segment(object):
"""the 2 points p1 and p2 are unordered"""
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
class Line(object):
"""p1 and p2 are 2 points in straight line"""
def __init__(self, p1, p2):
self.p1 = p1
self.p2 = p2
需要注意的是,这里并没有说线段的两个点是什么顺序(不一定说左边的点就是p1,右边就是p2)
2. 点与线的位置关系
(1) 计算点到直线的距离
如Fig.1(a)所示,现要求点 C 到直到直线
再由三角形知识可知,线段 AD 的长度为:
所以, AD−→− 可以这样计算: