我在上一篇博客中(详见:计算几何问题汇总–点与线的位置关系)谈到了计算几何最基本的问题:解决点与线(线段or直线)的位置关系判断。那么,更进一步,还需要探讨复杂一点的情况:比如面与线,面与面之间的关系。本文中,我就先说说最常见的两种几何图形:圆与矩形。我将就矩形与圆的碰撞判断问题、线与矩形、线与圆之间的碰撞问题作出分析,以及给出这些解决问题的算法、代码。
在此之前,我默认所有对本文内容感兴趣的读者,都了解基本的计算几何概念,并且对我的上一篇博客:计算几何问题汇总–点与线的位置关系 所讲的内容基本熟悉。因为本文涉及的算法,几乎全部都用到了上一篇博客中所定义的类和函数。
简单将上一篇博客的内容陈列如下,方便读者阅读后面本文的算法:
模块名:PointLine
class Point: 点类,两个属性,分别是横纵坐标x, y
class Segment: 线段类,两个属性,分别是两个端点p1, p2
class Line: 直线类,两个属性,分别是直线上任意两点p1, p2
class Vector: 向量类,以向量的起点和终点为参数,建立一个由横纵坐标为两个属性的类
func: pointDistance(p1, p2): 计算两点之间距离的函数。返回一个浮点型的值
func: pointToLine(C, AB): 计算点C到直线AB的距离。返回一个浮点型的值
func: pointInLine(C, AB): 判断点C是否在直线AB上。在,返回True;不在,返回False
func: pointInSegment(C, AB): 判断点C是否在线段AB上。在,返回True;不在,返回False
func: linesAreParallel(l1, l2): 判断两条直线l1, l2是否平行。平行,返回True;不平行,返回False
func: crossProduct(v1, v2): 计算两个向量叉积
func: segmentsIntersect(s1, s2): 判断两个线段是否相交
func: segmentIntersectsLine(segment, line): 判断一条线段和一条直线是否相交
好了,以上是我在上一篇博客中定义的类和函数,我把他们的基本功能,参数设置等等简要列在了上面,以便理解本文后面将要给出的代码。至于具体的算法及分析,请翻看我的上一篇博客。
需要注意的是,我在本文中,把上一篇博客的工作全部封装成了一个模块:PointLine.py
,方便本文的代码调用。
接下来,就进入本文的主题吧。
圆
1. 圆与点的位置关系
简单来分,二维空间内,圆与点的位置关系,只有两种:
(1)点在圆上(包括在圆周上以及在圆内);
(2)点在圆外
而判断的方法很直接,计算点到圆心的距离,再用这个距离和圆的半径比较即可。
先定义一个圆类:两个属性,圆心及半径。
class Circle(object):
"""Circle has 2 attributes: center and radius"""
def __init__(self, center, radius):
self.center = center
self.radius = radius
然后写出判断点与圆关系的完整代码如下:
from PointLine import *
class Circle(object):
"""Circle has 2 attributes: center and radius"""
def __init__(self, center, radius):
self.center = center
self.radius = radius
def pointInCircle(point, circle):
"""determine whether a point in a circle"""
return (pointDistance(point, circle.center) - circle.radius) < 1e-9
其中,pointDistance()
函数在模块 PointLine
已经存在。
最后的距离判断还是要满足浮点值比较的原则,上一篇博客中详细说过,不再赘述。
2. 圆与线的位置关系
(1) 圆与直线的位置关系
简单划分,还是两种:相交(包括相切);不相交
判断的依据是根据圆心到直线的距离与圆半径相比较。判别函数如下:
def lineIntersectsCircle(line, circle):
"""determine whether a line intersects a circle"""
dis = pointToLine(circle.center, line)
return dis - circle.radius < 1e-9
其中,pointToLine()
在模块PointLine
中已经存在。
(2) 圆与线段的位置关系
线段由于其位置上的限制,导致我们在判断线段和圆的关系的时候会麻烦一点。判断思路如下:
- 判断线段 s 所在的直线
l 与圆心的距离 dis 和圆的半径 r 之间的关系。若dis<=r 则进行2、3步的判断;若 dis>r ,直接返回False.(也就是说肯定与圆不相交) - 计算出圆心到直线 l 的垂线与直线
l 的交点(也就是垂足),记为点