计算几何问题汇总 您所在的位置:网站首页 almost的位置关系 计算几何问题汇总

计算几何问题汇总

2024-06-10 21:51| 来源: 网络整理| 查看: 265

http://www.infocool.net/kb/Python/201609/191671.html

点与点之间, 线与线之间,点与线之间的位置关系是一类非常重要的问题。它不仅是平面几何学的基石,也常常应用于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 123456

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

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

2. 两点之间距离的计算

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

为了和本文之后的问题保持编码风格上一致,同时简化代码编写。我使用对向量运算已经极为成熟的库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)) 1234567891011121314151617181920212223242526272829

说明一下,在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 1234567891011121314

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

2. 点与线的位置关系

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

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

cos∠CAB=AC−→⋅AB−→|AC−→|⋅|AB−→|

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

|AC−→|⋅cos∠CAB

所以,  AD−→−  可以这样计算:

AD−→−=AB−→|AB−→|⋅|AD−→−|=AB−→|AB−→|⋅|AC−→|⋅cos∠CAB=AB−→⋅AC−→|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) 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768

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

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

def pointInLine(C, AB): """determine whether a point is in a straight line""" return pointToLine(C, AB) < 1e-9 1234

(3) 判断点是否在线段上

处理完了点和直线的位置关系,我们接着来看点与线段的位置关系。其实,最常用的就是一点:判断点是否在线段上。这和判断点是否在直线上最大的区别在于线段有起点、终点。

如Fig.1(b)所示,判断点  C  在不在线段  AB  上,可以这样解决:

计算点  C  到线段  AB  所在直线的距离 若这个距离为0,继续第3步;否则,返回False 若点  C  的横坐标在点  A  与点  B  的横坐标之间,则返回True,否则返回False

函数如下:

def pointInSegment(C, AB): """determine whether a point is in a segment""" # if C in segment AB, it first in straight line AB if pointInLine(C, Line(AB.p1, AB.p2)): return min(AB.p1.x, AB.p2.x) >> False # 设点p4, p5得到一条与l1平行的直线l2 p4 = Point(0, 1) p5 = Point(2, 3) l2 = Line(p4, p5) print(linesAreParallel(l1, l2)) # >>> True # 计算p4到l1的距离 print(pointToLine(p4, l1)) # >>> 0.7071067... # 设两条线段s2, s3 s2 = Segment(Point(0, 2), Point(5, -1)) s3 = Segment(Point(1, 0.7), Point(5, -1)) # s2与s1相交;s3与s1不相交 print(segmentsIntersect(s2, s1)) # >>> True print(segmentsIntersect(s3, s1)) # >>> False


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有