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

前言

分离轴定理(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;
}

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值