使用分离轴定理对多边形进行碰撞检测

2024-08-30 04:44

本文主要是介绍使用分离轴定理对多边形进行碰撞检测,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

分离轴定理(SAT,Separating Axis Theorem)进行二维多边形碰撞检测是一种常见且有效的方法,用于二维多边形碰撞检测的基本思想是:如果两个凸多边形不相交,那么存在一条轴(线),使得这条轴上的投影会使两个多边形的投影不重叠。换句话说,如果我们找到一条轴,使得两个多边形在这条轴上的投影不重叠,那么我们可以确定两个多边形不会相交。

一、计算所有可能的分离轴

对于每个多边形,计算所有边的法向量作为可能的分离轴

对于每个边(即每条边的法向量),法向量是与边垂直的向量

// 计算一个向量的法向量
Vector2 perpendicular(const Vector2& v) {return Vector2(-v.y, v.x);
}// 计算多边形的边法向量
std::vector<Vector2> getPolygonAxes(const std::vector<Vector2>& polygon) {std::vector<Vector2> axes;size_t count = polygon.size();for (size_t i = 0; i < count; ++i) {Vector2 edge = polygon[(i + 1) % count] - polygon[i];axes.push_back(perpendicular(edge));}return axes;
}

二、将多边形投影到每个分离轴上

使用点积运算将多边形的每个顶点投影到分离轴上

计算这些投影的最小值和最大值,以确定投影区间。

// 投影一个多边形到一个轴上
std::pair<float, float> projectPolygon(const std::vector<Vector2>& polygon, const Vector2& axis) {float min = dot(polygon[0], axis);float max = min;for (const auto& vertex : polygon) {float projection = dot(vertex, axis);min = std::min(min, projection);max = std::max(max, projection);}return {min, max};
}// 检查两个多边形是否相交
bool polygonsIntersect(const std::vector<Vector2>& poly1, const std::vector<Vector2>& poly2) {std::vector<Vector2> axes = getPolygonAxes(poly1);std::vector<Vector2> axes2 = getPolygonAxes(poly2);// 将两个多边形的轴合并axes.insert(axes.end(), axes2.begin(), axes2.end());for (const auto& axis : axes) {auto proj1 = projectPolygon(poly1, axis);auto proj2 = projectPolygon(poly2, axis);if (!overlap(proj1, proj2)) {return false; // 找到一个分离轴,两个多边形不相交}}return true; // 没有找到分离轴,两个多边形相交
}

三、检查投影是否重叠 

对每条分离轴上的投影区间进行重叠检测。

如果在任何一个轴上投影区间不重叠,两个多边形就不会相交。

如果所有的轴上投影区间都重叠,那么两个多边形相交。

// 检查两个区间是否重叠
bool overlap(const std::pair<float, float>& a, const std::pair<float, float>& b) {return !(a.second < b.first || b.second < a.first);
}

四、测试源码 

#include <vector>
#include <iostream>
#include <algorithm> // For std::max and std::min// 表示二维向量
struct Vector2 {float x, y;Vector2(float x = 0, float y = 0) : x(x), y(y) {}
};// 计算两个向量的点积
float dot(const Vector2& a, const Vector2& b) {return a.x * b.x + a.y * b.y;
}// 计算两个向量的差
Vector2 operator-(const Vector2& a, const Vector2& b) {return Vector2(a.x - b.x, a.y - b.y);
}// 计算一个向量的法向量
Vector2 perpendicular(const Vector2& v) {return Vector2(-v.y, v.x);
}// 计算多边形的边法向量
std::vector<Vector2> getPolygonAxes(const std::vector<Vector2>& polygon) {std::vector<Vector2> axes;size_t count = polygon.size();for (size_t i = 0; i < count; ++i) {Vector2 edge = polygon[(i + 1) % count] - polygon[i];axes.push_back(perpendicular(edge));}return axes;
}// 投影一个多边形到一个轴上
std::pair<float, float> projectPolygon(const std::vector<Vector2>& polygon, const Vector2& axis) {float min = dot(polygon[0], axis);float max = min;for (const auto& vertex : polygon) {float projection = dot(vertex, axis);min = std::min(min, projection);max = std::max(max, projection);}return {min, max};
}// 检查两个区间是否重叠
bool overlap(const std::pair<float, float>& a, const std::pair<float, float>& b) {return !(a.second < b.first || b.second < a.first);
}// 检查两个多边形是否相交
bool polygonsIntersect(const std::vector<Vector2>& poly1, const std::vector<Vector2>& poly2) {std::vector<Vector2> axes = getPolygonAxes(poly1);std::vector<Vector2> axes2 = getPolygonAxes(poly2);// 将两个多边形的轴合并axes.insert(axes.end(), axes2.begin(), axes2.end());for (const auto& axis : axes) {auto proj1 = projectPolygon(poly1, axis);auto proj2 = projectPolygon(poly2, axis);if (!overlap(proj1, proj2)) {return false; // 找到一个分离轴,两个多边形不相交}}return true; // 没有找到分离轴,两个多边形相交
}int main() {std::vector<Vector2> poly1 = {Vector2(0, 0), Vector2(1, 0),Vector2(1, 1), Vector2(0, 1)};std::vector<Vector2> poly2 = {Vector2(0.5, 0.5), Vector2(1.5, 0.5),Vector2(1.5, 1.5), Vector2(0.5, 1.5)};if (polygonsIntersect(poly1, poly2)) {std::cout << "Polygons intersect!" << std::endl;} else {std::cout << "Polygons do not intersect." << std::endl;}return 0;
}

这篇关于使用分离轴定理对多边形进行碰撞检测的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119834

相关文章

Python常用命令提示符使用方法详解

《Python常用命令提示符使用方法详解》在学习python的过程中,我们需要用到命令提示符(CMD)进行环境的配置,:本文主要介绍Python常用命令提示符使用方法的相关资料,文中通过代码介绍的... 目录一、python环境基础命令【Windows】1、检查Python是否安装2、 查看Python的安

Python并行处理实战之如何使用ProcessPoolExecutor加速计算

《Python并行处理实战之如何使用ProcessPoolExecutor加速计算》Python提供了多种并行处理的方式,其中concurrent.futures模块的ProcessPoolExecu... 目录简介完整代码示例代码解释1. 导入必要的模块2. 定义处理函数3. 主函数4. 生成数字列表5.

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用