一种3D空间的柱状多边形检测实现

 

最近无意中拓展出这个东西,基于之前写的2D多边形检测:

http://www.cnblogs.com/hont/p/6105997.html

而判断两条线相交的方法替换成了我后来写的差乘判断:

http://www.cnblogs.com/hont/p/6106043.html

 

该功能在多边形选区与地形处理上应用较广泛

代码实现:

复制代码
using UnityEngine;

public class Test : MonoBehaviour
{
    public Transform testComparePoint;//比较点
    public Transform[] pointsArray;//比较多边形每个点
    public float height = 4;//比较多边形高度


    public bool IsInRange(Vector3 comparePoint)
    {
        Vector3 localComparePoint = transform.worldToLocalMatrix.MultiplyPoint3x4(comparePoint);
        //将比较点从世界转本地空间

        bool flag = true;
        flag &= localComparePoint.y <= height;
        flag &= localComparePoint.y >= -height;
        flag &= IsConcaveContain2D(pointsArray, localComparePoint);

        if (flag)
            return true;

        return false;
    }

    public bool IsConcaveContain2D(Transform[] points, Vector3 compare)
    {
        const float kVirtualRaycastLen = 100000f;

        Vector3 comparePoint = (points[1].localPosition + points[0].localPosition) * 0.5f;
        Vector3 originPoint = compare;
        comparePoint += (comparePoint - originPoint).normalized * kVirtualRaycastLen;

        int count = 0;
        for (int i = 0; i < points.Length; i++)
        {
            Transform a = points[i % points.Length];
            Transform b = points[(i + 1) % points.Length];

            bool r = IsLineSegmentIntersection(a.localPosition, b.localPosition, originPoint, comparePoint);

            if (r) count++;
        }

        return count % 2 == 1;
    }

    //判断ab与cd线段是否相交
    public bool IsLineSegmentIntersection(Vector3 a, Vector3 b, Vector3 c, Vector3 d)
    {
        float crossA = Vector3.Cross(d - c, a - c).y;
        float crossB = Vector3.Cross(d - c, b - c).y;

        if (!(crossA > 0f ^ crossB > 0f)) return false;

        float crossC = Vector3.Cross(b - a, c - a).y;
        float crossD = Vector3.Cross(b - a, d - a).y;

        if (!(crossC > 0f ^ crossD > 0f)) return false;

        return true;
    }

    private void OnDrawGizmos()
    {
        if (pointsArray == null) return;

        if (testComparePoint)
        {
            Vector3 comparePoint = testComparePoint.transform.position;
            if (IsInRange(comparePoint))
                Gizmos.color = Color.red;
        }

        Gizmos.matrix = transform.localToWorldMatrix;

        for (int i = 0; i < pointsArray.Length; i++)
        {
            Transform a = pointsArray[i];
            Transform b = pointsArray[(i + 1) % pointsArray.Length];

            if (!a || !b) continue;

            Vector3 minA = a.localPosition;
            Vector3 minB = b.localPosition;

            Vector3 maxA = a.localPosition;
            Vector3 maxB = b.localPosition;

            minA.y = -height;
            minB.y = -height;

            maxA.y = height;
            maxB.y = height;

            Gizmos.DrawLine(minA, minB);
            Gizmos.DrawLine(maxA, maxB);

            Gizmos.DrawLine(minA, maxA);
            Gizmos.DrawLine(minB, maxB);
        }
    }
}
复制代码

 

posted @   HONT  阅读(584)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示
回到顶部