当前位置: 首页 > article >正文

分离轴定理检测两个凸多边形是否相交

1、什么是分离轴定理?

通过检查两个物体在所有可能的分离轴上的投影是否重叠,来判断它们是否相交。如果存在任何一个分离轴上的投影不重叠,那么两个物体一定不相交。否则,如果所有的分离轴上的投影都重叠,那么两个物体可能相交,需要进一步检查。

如上图,我们可以找到一条分离轴(不唯一),使得三角形的投影线段HI和四边形的投影线段JK不重叠,则两个多边形不相交。

2、怎么确定分离轴

  1. 对于每个物体的边界框,确定其边界框的边或面的法线向量。

  2. 对于每个法线向量,检查两个物体在该法线上的投影是否重叠。如果所有法线上的投影都重叠,那么两个物体一定相交。如果至少一条法线上的投影不重叠,那么两个物体一定不相交。

3、Unity代码实现

    /// <summary>
    /// 判断是否相交
    /// </summary>
    /// <param name="verShapeA">多边形A</param>
    /// <param name="verShapeB">多边形B</param>
    /// <returns></returns>
    private bool IsCross(List<Vector2Int> verShapeA,List<Vector2Int> verShapeB)
    {
        for (int i = 0; i < verShapeA.Count; i++)
        {
            Vector2Int a, b;
            a = verShapeA[i];
            if (i == verShapeA.Count - 1)
            {
                b = verShapeA[0];
            }
            else
            {
                b = verShapeA[i + 1];
            }

            //求边的单位法向量
            Vector2 normalVector = GetNormalVector(a, b);
            //求shapeA在向量上的最低点和最高点
            Vector2 minShapeAPos, maxShapeAPos=Vector2.zero;
            GetShapeProjectLength(verShapeA,normalVector,out minShapeAPos,out maxShapeAPos);
            //求shapeB在向量上的最低点和最高点
            Vector2 minShapeBPos,maxShapeBPos=Vector2.zero;
            GetShapeProjectLength(verShapeB,normalVector,out minShapeBPos,out maxShapeBPos);
            //检查两段投影是否有交集
            if (Mathf.Min(maxShapeAPos.y, maxShapeBPos.y) - Mathf.Max(minShapeAPos.y, minShapeBPos.y) > 0)
            {
                continue;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    
    //求边的法向量
    private Vector2 GetNormalVector(Vector2Int pos1, Vector2Int pos2)
    {
        Vector2Int edgeVector = pos2 - pos1;
        return new Vector2(-edgeVector.y, edgeVector.x).normalized;
    }
    
    //求shape在法向量的投影最低点和最高点
    private void GetShapeProjectLength(List<Vector2Int> verShape,Vector2 normal,out Vector2 lowPos,out Vector2 highPos)
    {
        lowPos = new Vector2(0, float.MaxValue);
        highPos = new Vector2(0, float.MinValue);
        for (int i = 0; i < verShape.Count; i++)
        {
            float dotProduct = Vector2.Dot(verShape[i], normal);
            Vector2 projectionPoint = dotProduct*(Vector2)normal;
            if (projectionPoint.y < lowPos.y)
            {
                lowPos = projectionPoint;
            }

            if (projectionPoint.y > highPos.y)
            {
                highPos = projectionPoint;
            }
        }
    }

4、效果

采样集较少,不一定能保证算法100%正确(至少检测了10多个案例都是符合预期的)

5、缺点

分离轴定理算法只适用于凸多边形 and 无法告诉你是那条边发生的碰撞


http://www.kler.cn/a/429710.html

相关文章:

  • Pcl联合Qt显示点云
  • Entity 的材质(棋盘、条纹、网格)
  • 详解 Docker 启动 Windows 容器第二篇:技术原理与未来发展方向
  • 使用Deepseek搭建类Cursor编辑器
  • 【学习】【记录】【分享】微型响应系统
  • 数据结构(Java版)第八期:LinkedList与链表(三)
  • AI驱动的低代码平台:解密背后的算法与架构创新
  • STC单片机I2C驱动例程
  • psmisc移植到ARM Linux环境
  • 【EthIf编译脚本】communication/EthIf/EthIf.mod.mk
  • 夜莺运维指南之自定义告警模板
  • C/C++流星雨
  • 使用php生成、识别二维码
  • ElasticSearch如何做性能优化?
  • Online Monocular Lane Mapping
  • vba学习系列(9)--按需求计数单元格数量
  • vue之$emit 获取返回值
  • 数字孪生与大型模型强强联合,共塑工业制造崭新前景
  • .NET用C#导入Excel数据到数据库
  • 面试技术点之安卓篇
  • 游戏AI实现-有限状态机
  • 通过Zynq FPGA对雷龙SD NAND进行测试
  • 黑马商城docker部署部分MySQL拉取超时解决方法
  • 前端学习纪要
  • java八股-流量封控系统
  • Leetcode 每日一题 1.两数之和