分离轴定理SAT凸多边形精确碰撞检测

分离轴定理SAT凸多边形精确碰撞检测

定理

Separating Axis Theorem,缩写SAT,中文为分离轴理论分离轴定理,通过判断凸多边形在分离轴上的投影是否重叠来判断是否发生碰撞。

所谓的分离轴实际上是一个方向轴,该轴的选取在二维平面情况下一般为凸多边形的边的法线

局限性:分离轴定理仅适用于凸多边形,不能用于凹多边形。但可以通过转化的方法,即将凹多边形转化为多个凸多边形,然后对多个凸多边形分别使用SAT,达到精确碰撞检测的目的

证明

证明过程可以看SAT(分离轴定理)证明 - 知乎 (zhihu.com)

代码

2D

我们先来探讨二维平面下的情况

步骤大概有如下几步:

  • 获取其中一个凸多边形每个边的垂直向量(法向量)
  • 点乘获得投影(这里不用除以法向量的模,因为对判断碰撞无影响),其中所有结果中的最小值和最大值就是获得的投影(这里是把两个值当作投影线段两端点在分离轴这个一维数轴的坐标了)
  • 判断投影是否相交

以下是代码,每一步还可以进一步优化,这里代码仅为阐述上述步骤

# 获取边的法向量
def getNormal(points: list)->list:
    normalVec = {}      # 法向量的集合(Set)
    for i in points:
        for j in points[points.index(i)::]:
            # edge = (i[0]-j[0], i[1]-j[1])   #边对应的向量
            vec = (j[1]-i[1], i[0]-j[0])    # 法线对应的向量。可以看出(x,y)垂直的一个向量为(-y,x)
            normalVec.add(vec)
    return list(normalVec)

# 点乘,获取所有结果中的最大值与最小值
def dotProduct(lst1:list, lst2:list)->list:
    res = []
    for i in lst1:
        for j in lst2:
            res.append(i[0]*j[0] + i[1]*j[1])
    return (min(res), max(res))

# 碰撞检测
def collided(points1:list, points2:list)->bool:
    vec = getNormal(points1)
    res1 = dotProduct(vec, points1)
    res2 = dotProduct(vec, points2)

    # 判断重影是否重叠,重叠就发生碰撞返回True
    if (res1[0]<=res2[1] and res1[0]>=res2[0]) or (res1[1]<=res2[1] and res1[1]>=res2[0]):
        return True
    else:
        return False

# ------------ 调用---------------#
# 这里存放点的列表仅做表示,获取点的方法根据自己情况来

# 存放凸多边形1顶点的列表
shape1_points = []
# 存放凸多边形2顶点的列表
shape2_points = []

print(collided(shape1_points, shape2_points))

3D

其实3D步骤也一样,只不过分离轴凸多边形边的法向量凸多面体的面的法向量

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在MATLAB中,可以使用分离定理来实现自动泊车过程中的碰撞检测分离定理是一种用于检测两个凸多边形是否相交的方法。它的基本思想是,如果两个凸多边形之间不存在分离轴,那么它们一定相交。 在自动泊车过程中,我们可以将车辆和障碍物都抽象为凸多边形。然后,使用MATLAB中的向量运算和凸多边形的相关函数,计算出车辆和障碍物的所有可能的分离轴,并检测它们是否存在相交。如果存在相交,则说明车辆会与障碍物碰撞。 以下是一个简单的示例代码,用于检测两个凸多边形是否相交: ```matlab function result = check_collision(polygon1, polygon2) % polygon1和polygon2分别为两个凸多边形的顶点坐标 % 返回值为0表示没有碰撞,返回值为1表示有碰撞 % 计算所有可能的分离轴 axes = [polygon1(2:end,:) - polygon1(1:end-1,:); polygon1(1,:) - polygon1(end,:)]; axes = [axes; polygon2(2:end,:) - polygon2(1:end-1,:); polygon2(1,:) - polygon2(end,:)]; axes = unique(axes, 'rows'); axes = axes ./ vecnorm(axes, 2, 2); % 检测每个分离轴是否存在相交 for i = 1:size(axes, 1) proj1 = polygon1 * axes(i,:)'; proj2 = polygon2 * axes(i,:)'; if max(proj1) < min(proj2) || max(proj2) < min(proj1) result = 0; return; end end % 如果所有分离轴都不存在相交,则说明存在碰撞 result = 1; end ``` 在实际使用中,我们可以将上述代码嵌入到自动泊车的程序中,每隔一定时间调用一次该函数,检测车辆和障碍物是否存在碰撞。如果存在碰撞,则及时停车或调整车辆方向,避免发生事故。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值