首页 > 代码库 > 一种3D空间的柱状多边形检测实现

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

技术分享

 

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

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

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

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

 

应用还是比较广泛的,特别是多边形选区和地形处理上

 

 

代码:

using UnityEngine;
using System.Linq;
using System.Collections;

public class Test : MonoBehaviour
{
    public Transform testComparePoint;
    public Transform[] pointsArray;
    public float height = 4;


    public bool IsInRange(Vector3 comparePoint)
    {
        if (comparePoint != null)
        {
            var flag = true;
            flag &= comparePoint.y <= height;
            flag &= comparePoint.y >= -height;
            flag &= IsConcaveContain2D(pointsArray, comparePoint);

            if (flag)
                return true;
        }

        return false;
    }

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

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

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

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

            if (r) count++;
        }

        return count % 2 == 1;
    }

    public bool IsLineSegmentIntersection(Vector3 a, Vector3 b, Vector3 c, Vector3 d)
    {
        var crossA = Mathf.Sign(Vector3.Cross(d - c, a - c).y);
        var crossB = Mathf.Sign(Vector3.Cross(d - c, b - c).y);

        if (crossA == crossB) return false;

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

        if (crossC == crossD) return false;

        return true;
    }

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

        if (testComparePoint != null)
        {
            var comparePoint = transform.InverseTransformPoint(testComparePoint.transform.position);
            if (IsInRange(comparePoint))
            {
                Gizmos.color = Color.red;
            }
        }

        var cacheMatrix = Gizmos.matrix;
        Gizmos.matrix = transform.localToWorldMatrix;

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

            if (a == null) continue;
            if (b == null) continue;

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

            var maxA = a.localPosition;
            var 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);
        }

        Gizmos.color = Color.clear;

        Gizmos.matrix = cacheMatrix;
    }
}

 

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