zoukankan      html  css  js  c++  java
  • 2D空间中求一点是否在多边形内

    参考自这篇博文:http://www.cnblogs.com/dabiaoge/p/4491540.html

    一开始没仔细看做法,浪费了不少时间。下面是最终实现的效果:

    大致流程:

    1.随便选取多边形上任意一条边,以比较点和边的中心点做一条射线(这里用的伪射线)。

    2.用这条射线与其他所有边判断是否相交。

    3.将所有与线段相交的数量相加,如果是奇数就在多边形内。

    特殊情况:

    1.刚好在点上或者在线上。实际运用时会有点误差,但不影响。

    2.必须是闭合线段,且不能存在包含的情况。但如果是一个数组生成的线段,不会有这种情况

    代码(Unity3D):

    using UnityEngine;
    using System.Collections;
    
    public class Test1 : MonoBehaviour
    {
        const float RAYCAST_LEN = 100000f;
        public Transform[] points;
        public Transform compare;
    
    
        bool IsContract(Transform compare)
        {
            var comparePoint = (points[1].position + points[0].position) * 0.5f;
            var originPoint = compare.transform.position;
            comparePoint += (comparePoint - originPoint).normalized * RAYCAST_LEN;
    
            Debug.DrawLine(originPoint, comparePoint);
    
            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 = IsIntersection(a.position, b.position, originPoint, comparePoint);
    
                if (r) count++;
            }
    
            return count % 2 == 1;
        }
    
        void OnDrawGizmos()
        {
            if (compare == null) return;
    
            var oldColor = Gizmos.color;
    
            if (IsContract(compare))
                Gizmos.color = Color.red;
    
            for (int i = 0; i < points.Length; i++)
            {
                var a = points[i % points.Length];
                var b = points[(i + 1) % points.Length];
    
                Gizmos.DrawLine(a.position, b.position);
            }
    
            Gizmos.color = oldColor;
        }
    
        bool IsIntersection(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 (Mathf.Approximately(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 (Mathf.Approximately(crossC, crossD)) return false;
    
            return true;
        }
    }

    另外参考的文章中没有说差乘判断两个线段是否相交的具体做法,这里说明一下

    大致流程:

    现在有线段AB和线段CB

    用线段AB的方向和C,D两点分别做差乘比较。如果C,D在同侧则return跳出

    用线段CD的方向和A,B两点分别做差乘比较。如果A,B在同侧则return跳出

    最终返回相交

    脚本就是上面的IsIntersection函数,最终实现效果(只适用于2D空间,如果是XY轴向要取差乘的z分量做比较):

  • 相关阅读:
    路由
    更改HTTP头信息
    laravel 笔记
    laraven安装记录
    虚拟机Centos设置静态IP
    关于正向代理,反向代理,负载均衡的个人理解
    exce族函数详解
    【C】多线程编程笔记
    【转】Linux C 网络编程——TCP套接口编程
    MySQL 用户管理及权限管理
  • 原文地址:https://www.cnblogs.com/hont/p/6105997.html
Copyright © 2011-2022 走看看