图形几何算法 -- 判断多边形是否相交

前言

        判断多边形是否相交是计算几何中的一个重要问题。这个问题在图形学、地理信息系统、计算机视觉等领域都有广泛的应用。下面介绍判断多边形相交的基本概念、方法和实现步骤。

        判断多边形是否相交的算法有多种,今天这里介绍的是Separate Axis Theorem(SAT)的算法原理。

关于SAT的概念

       分离轴定理(Separating Axis Theorem, SAT)是一种用于检测两个凸多边形是否相交的有效方法。根据该定理,如果存在一种直线(分离轴),使得两个多边形在该直线上的投影不重叠,则这两个多边形不相交。反之,如果所有投影都重叠,则这两个多边形相交。

SAT 算法步骤

  1. 计算每个多边形的边向量:对于多边形的每一条边,计算其法向量(即垂直于边的向量)。
  2. 投影多边形到法向量:对所有顶点进行投影,找到两个多边形在这个法向量上的最小和最大值。
  3. 检查重叠:如果投影有重叠,则继续检查其他法向量。如果找到任何一个法向量的投影不重叠,则这两个多边形不相交。

完整代码

以下是一个实现SAT用于判断两个2D凸多边形是否相交的示例代码

using System;
using System.Collections.Generic;
using System.Linq;

public class Vector
{
    public float X { get; }
    public float Y { get; }

    public Vector(float x, float y)
    {
        X = x;
        Y = y;
    }

    public static Vector operator -(Vector a, Vector b)
    {
        return new Vector(a.X - b.X, a.Y - b.Y);
    }

    public static float Dot(Vector a, Vector b)
    {
        return a.X * b.X + a.Y * b.Y;
    }

    public static Vector Perpendicular(Vector v)
    {
        return new Vector(-v.Y, v.X); // 顺时针旋转90度
    }
}

public class Polygon
{
    public List<Vector> Vertices { get; }

    public Polygon(List<Vector> vertices)
    {
        Vertices = vertices;
    }

    public List<Vector> GetEdges()
    {
        List<Vector> edges = new List<Vector>();

        for (int i = 0; i < Vertices.Count; i++)
        {
            Vector start = Vertices[i];
            Vector end = Vertices[(i + 1) % Vertices.Count];
            edges.Add(end - start);
        }

        return edges;
    }

    public List<Vector> GetNormals()
    {
        List<Vector> normals = new List<Vector>();
        foreach (Vector edge in GetEdges())
        {
            normals.Add(Vector.Perpendicular(edge));
        }
        return normals;
    }

    public (float min, float max) ProjectOntoAxis(Vector axis)
    {
        float min = float.MaxValue;
        float max = float.MinValue;

        foreach (Vector vertex in Vertices)
        {
            float projection = Vector.Dot(vertex, axis);
            min = Math.Min(min, projection);
            max = Math.Max(max, projection);
        }

        return (min, max);
    }
}

public static class SAT
{
    public static bool ArePolygonsIntersecting(Polygon polyA, Polygon polyB)
    {
        foreach (Vector normal in polyA.GetNormals())
        {
            if (!IsProjectionOverlapping(polyA, polyB, normal))
                return false;
        }

        foreach (Vector normal in polyB.GetNormals())
        {
            if (!IsProjectionOverlapping(polyA, polyB, normal))
                return false;
        }

        return true; // 如果在所有轴投影上都有重叠,则多边形相交
    }

    private static bool IsProjectionOverlapping(Polygon polyA, Polygon polyB, Vector axis)
    {
        var (aMin, aMax) = polyA.ProjectOntoAxis(axis);
        var (bMin, bMax) = polyB.ProjectOntoAxis(axis);

        return aMax >= bMin && bMax >= aMin; // 重叠条件
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        // 定义两个多边形
        Polygon polyA = new Polygon(new List<Vector>
        {
            new Vector(1, 1),
            new Vector(3, 1),
            new Vector(3, 3),
            new Vector(1, 3)
        });

        Polygon polyB = new Polygon(new List<Vector>
        {
            new Vector(2, 2),
            new Vector(4, 2),
            new Vector(4, 4),
            new Vector(2, 4)
        });

        bool isIntersecting = SAT.ArePolygonsIntersecting(polyA, polyB);
        Console.WriteLine("Polygons intersect: " + isIntersecting);
    }
}

代码解释:

  1. Vector 类:表示一个二维向量,提供向量相减、点积和垂直操作的方法。
  2. Polygon 类:表示一个多边形,包含顶点列表。其方法包括获得边、法向量和投影到给定轴上。
  3. SAT 类:包含用于检测两个多边形是否相交的逻辑:

               ArePolygonsIntersecting` 方法会对每个多边形的法向量进行重叠检。

               IsProjectionOverlapping` 方法检查两个多边形在投影轴上的重叠情况。

  1. Program 类:在 `Main` 方法中创建两个多边形并检查它们是否相交。

使用说明:

        此代码演示了如何使用分离轴定理检测两个凸多边形的相交情况。在实际应用中,您可能需要将其扩展到处理凹多边形,或添加更多功能。对于凹多边形的处理,可以先将其细分为多个凸多边形进行检测。

更多学习内容,可关注公众号:

 

以上内容为个人测试过程的记录,供大家参考。

内容如有错欢迎批评指正,谢谢!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值