程序员人生 网站导航

计算几何问题汇总--点与线的位置关系

栏目:php教程时间:2016-09-26 08:53:10

点与点之间, 线与线之间,点与线之间的位置关系是1类非常重要的问题。它不但是平面几何学的基石,也常常利用于LBS(Location Based Service),社交网络,和数据库查询等领域。

本文中,我将给出判断这些关系的相干算法,作为参考。需要说明的是,我给出的这些问题的解法,都是建立在2维平面空间之上。有关多维空间的位置关系,大家可以仿照2维空间中问题的思路,做相应的拓展。

语言上,我用确当然还是Python.

点与点之间的距离

先从最简单的点与点的位置关系说起。1般情况下,我们只关心点与点之间的距离。

1. 点类的定义

为使算法思路更加清晰,先定义点类Point,既然是在2维空间上,那末每一个点都应当有两个属性:x, y分别代表点的横纵坐标。

class Point(object): """Point are two-dimension""" def __init__(self, x, y): self.x = x self.y = y

接下来就看看如何计算两点之间距离:固然可以用初中学的欧氏距离最基本的计算方法。但是斟酌到代码编写的效力,和方便以后向高维空间拓展。我在本文中将尽可能使用向量计算。

而为了简化代码,我们使用对向量运算已相当做熟的库numpy

2. 两点之间距离的计算

明显,两点可以构成向量,而向量的长度则是其内积的开方。空间中,点A与点B的距离可以用向量AB的模|AB|表示。所以,现在需要做的,就是写1个函数,以两点为参数,计算由这两点构成的向量的模。

为了和本文以后的问题保持编码风格上1致,同时简化代码编写。我使用对向量运算已极其成熟的库numpy帮助计算。并且定义了1个新的类Vector,类Vector以向量的出发点和终点作为输入,生成1个只具有属性x和y的向量对象。

最后,和前面定义的类放在1起,代码以下:

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))

说明1下,在Python3.5以后的版本中,使用numpy库时,ndarray对象之间的乘法可以用@,代替之前的v1.dot(v2)这样的情势。

点与线之间的位置关系

1. 线的分类

点与线之间的位置关系就要略微复杂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

需要注意的是,这里并没有说线段的两个点是甚么顺序(不1定说左侧的点就是p1,右侧就是p2)

2. 点与线的位置关系

(1) 计算点到直线的距离

如Fig.1(a)所示,现要求点C到直到直线AB的距离。还是向量法,据向量知识可知:

cosCAB=ACAB|AC||AB|


再由3角形知识可知,线段AD的长度为:

|AC|cosCAB


所以,AD可以这样计算:

AD=AB|AB||AD|=AB|AB||AC|cosCAB=ABAC|AB|2AB


AD计算完成以后,可以根据AD相应的坐标值得到点D的坐标,再由上面点和点之间的距离,便可得到线段CD的长度。

这里写图片描述

给出完全的代码以下:

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 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 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)) def pointToLine(C, AB): """calculate the shortest distance between point C and straight line AB, return: a float value""" # two Vector object vector_AB = Vector(AB.p1, AB.p2) vector_AC = Vector(AB.p1, C) # two ndarray object tAB = np.array([vector_AB.x, vector_AB.y]) tAC = np.array([vector_AC.x, vector_AC.y]) # vector AD, type: ndarray tAD = ((tAB @ tAC) / (tAB @ tAB)) * tAB # get point D Dx, Dy = tAD[0] + AB.p1.x, tAD[1] + AB.p1.y D = Point(Dx, Dy) return pointDistance(D, C)

(2) 判断点是不是在直线上
既然已能够计算点到直线的距离了,那末,只需要看点到直线的距离是不是为0便可知道这个点在不在直线上。

接着上面的代码,可以写出以下函数:

def pointInLine(C, AB): """determine whether a point is in a straight line""" return pointToLine(C, AB) <
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐