判断点是否在一个任意多边形中

using UnityEngine;
using System.Collections.Generic;

public class JudgePoint : MonoBehaviour
{

//多边形A 所有顶点
private float[,] dingdian = new float[4, 3] { { 6, 4, 0 }, { 3, 1, 0 }, { 2, 2, 0 }, { 3, 5, 0 } };
//P点 不确定是否在多边形内
private float[,] P = new float[1, 3] { { 3, 2, 0 } };
//O点 目标点
private float[,] O = new float[1, 3] { { 7, 10, 0 } };
//测试 不规则四边形 第一象限
private float[,] bianbian = new float[4, 3] { { 8, 0, 8 }, { 2, 2, 0 }, { 0, 5, 0 }, { 4, 8, 0 } };
private float[,] dian1 = new float[1, 3] { { 5, 8, 0 } };//坐标系中不在多边形内 unity测试 不在多边形内
private float[,] dian2 = new float[1, 3] { { 5, 2, 0 } };//坐标系中 在多边形内 unity测试 在多边形内
//测试 不规则五边形 410 260 480 770 830 第一象限
private float[,] bianFive = new float[5, 3] { { 4, 1, 0 }, { 2, 6, 0 }, { 4, 8, 0 }, { 7, 7, 0 }, { 8, 3, 0 } };
private float[,] dian3 = new float[1, 3] { { 2, 3, 0 } };//坐标系中 不在 unity测试 不在
private float[,] dian4 = new float[1, 3] { { 6, 3, 0 } };//坐标系中 在 unity测试 在
//7,8 不在 4,7在
//测试 多边形 不在第一象限内 180 650 520 -1-10 -820 -460
private float[,] bianSix = new float[6, 3] { { 1, 8, 0 }, { 6, 5, 0 }, { 5, 2, 0 }, { -1, -1, 0 }, { -8, 2, 0 }, { -4, 6, 0 } };
private float[,] dian7 = new float[1, 3] { { 5, 1, 0 } }; //坐标系 不在 unity不在
private float[,] dian8 = new float[1, 3] { { -4, -2, 0 } };//坐标系 不在 unity不在
private float[,] dian9 = new float[1, 3] { { 4, 5, 0 } }; //坐标系 在 unity在
//10000次 测试 不规则六边形 31毫秒
//10000次 测试 不规则四边形 15-16毫秒

//算法一:凹多边形测试 500 070 440 880 算法一 无法计算 凹多边形
private float[,] bianAo = new float[4, 3] { { 5, 0, 0 }, { 0, 7, 0 }, { 4, 4, 0 }, { 8, 8, 8 } };
private float[,] dian10 = new float[1, 3] { { 4, 5, 0 } }; //坐标系 不在 unity 不在
private float[,] dian11 = new float[1, 3] { { 5, 4, 0 } };//坐标系 在 unity 不在
//算法二:凹多边形测试 成功 10000次 凹四边形 15-16毫秒
//算法二测试:凹六边形 380 450 870 700 220 060 +判断点是否在边上
private float[,] bianAoSix = new float[6, 3] { { 3, 8, 0 }, { 4, 5, 0 }, { 8, 7, 0 }, { 6, 2, 0 }, { 2, 2, 0 }, { 0, 6, 0 } };
private float[,] dian12 = new float[1, 3] { { 8, 1, 0 } }; // 坐标系 不在 2 :0
private float[,] dian13 = new float[1, 3] { { 5, 6, 0 } };//坐标系 不在 3:2
private float[,] dian14 = new float[1, 3] { { 6, 1, 0 } };//坐标系 在 1 : 1
private float[,] dian15 = new float[1, 3] { { 3, 6, 0 } };//坐标系 在 2:3
//继续测试
private float[,] dian16 = new float[1, 3] { { 1, 2, 0 } };//坐标系 不在 0: 3
private float[,] dian17 = new float[1, 3] { { 3, 1, 0 } };//坐标系 不在 0: 2
private float[,] dian18 = new float[1, 3] { { 4, 8, 0 } };//不在 2: 0
private float[,] dian19 = new float[1, 3] { { 4, 7, 0 } };//不在 2: 2

//总结 算法一:适合任何凸多边形 任何象限 10000次 四边形 15-16毫秒
// 算法二:适合任何凹多边形 任何象限 10000次 四边形 0-15-16毫秒
// 算法二:加上判断点是否在边上 任何象限 10000次 六边形 15-16毫秒

private float[,] dian20 = new float[1, 3] { { 4, 4, 0 } };


void Start()
{
//ForJudgePoint(dingdian, P);
//ForJudgePoint(bianbian, dian);
//ForJudgePoint(bianFive, dian3);
//ForJudgePoint(bianFive, dian4);
//ForJudgePoint(bianSix, dian7);
//ForJudgePoint(bianSix, dian8);
//ForJudgePoint(bianSix, dian9);
float time = System.Environment.TickCount; //计时器
//for (int i = 0; i < 10000; i++)
//{
// ForJudgePoint(bianbian, dian2);
//}

// Debug.Log(Vector3.Angle(v1, v2));
//ForJudgePoint(bianAo, dian10);
//ForJudgePoint(bianAo, dian11);
//SecondJudge(bianAo, dian11);
for (int i = 0; i < 10000; i++)
{
SecondJudge(bianAo, dian10);
}
Debug.Log("times:" + (System.Environment.TickCount - time)); //计时器
//ForJudgePoint(bianSix, dian7);
//SecondJudge(bianSix, dian7);
//ForJudgePoint(bianSix, dian9);
//SecondJudge(bianSix, dian9);
//SecondJudge(bianAoSix, dian12);
//SecondJudge(bianAoSix, dian13);
//SecondJudge(bianAoSix, dian14);
//SecondJudge(bianAoSix, dian15);
//SecondJudge(bianAoSix, dian16);
//SecondJudge(bianAoSix, dian17);
//SecondJudge(bianAoSix, dian18);
//SecondJudge(bianAoSix, dian19);
//SecondJudge(bianAoSix, dian20);

}
//算法二 凹多边形
public void SecondJudge(float[,] dingdian, float[,] point)
{
int bianShu = dingdian.Length / 3;
//bool isOnLine = JudPointOnLine(dingdian, point, bianShu);
//if (isOnLine == true) { Debug.Log("该点在多边形边上"); return; }
List<int> listLeft = new List<int>();
List<int> listRight = new List<int>();
float y = point[0, 1];
float x = point[0, 0];
bool isEqu = false;
float bianX = 0;
for (int i = 0; i < bianShu; i++)
{
if (dingdian[i, 1] == y)
{
isEqu = true;
bianX = dingdian[i, 0];
if (dingdian[i, 0] > x)
{
listRight.Add(i);
listRight.Add(i);
}
else
{
listLeft.Add(i);
listLeft.Add(i);
}
}
}
for (int i = 0; i < bianShu; i++)
{
if (i < bianShu - 1)
{
if (dingdian[i, 1] < y && y < dingdian[i + 1, 1])
{
if (dingdian[i, 0] <= x && dingdian[i + 1, 0] <= x)
{
listLeft.Add(i);
}
else if (dingdian[i, 0] >= x && dingdian[i + 1, 0] >= x)
{
listRight.Add(i);
}
else
{
float midX = (dingdian[i, 0] + dingdian[i + 1, 0]) / 2;
if (x > midX)
{
listLeft.Add(i);
}
else
{
listRight.Add(i);
}
}
}
}
else
{
if (dingdian[i, 1] < y && y < dingdian[0, 1])
{
if (dingdian[i, 0] <= x && dingdian[0, 0] <= x)
{
listLeft.Add(i);
}
else if (dingdian[i, 0] >= x && dingdian[0, 0] >= x)
{
listRight.Add(i);
}
else
{
float midX = (dingdian[i, 0] + dingdian[0, 0]) / 2;
if (midX < x)
{
listLeft.Add(i);
}
else
{
listRight.Add(i);
}
}
}
}
}
for (int i = 0; i < bianShu; i++)
{
if (i < bianShu - 1)
{
if (dingdian[i, 1] > y && y > dingdian[i + 1, 1])
{
if (dingdian[i, 0] <= x && dingdian[i + 1, 0] <= x)
{
listLeft.Add(i);
}
else if (dingdian[i, 0] >= x && dingdian[i + 1, 0] >= x)
{
listRight.Add(i);
}
else
{
float midX = (dingdian[i, 0] + dingdian[i + 1, 0]) / 2;
if (midX < x)
{
listLeft.Add(i);
}
else
{
listRight.Add(i);
}
}
}
}
else
{
if (dingdian[i, 1] > y && y > dingdian[0, 1])
{
if (dingdian[i, 0] <= x && dingdian[0, 0] <= x)
{
listLeft.Add(i);
}
else if (dingdian[i, 0] >= x && dingdian[0, 0] >= x)
{
listRight.Add(i);
}
else
{
float midX = (dingdian[i, 0] + dingdian[0, 0]) / 2;
if (midX < x)
{
listLeft.Add(i);
}
else
{
listRight.Add(i);
}
}
}
}
}
//Debug.Log(listLeft.Count + " " + listRight.Count);
if (isEqu == false)
{
if (listLeft.Count % 2 == 0 || listRight.Count % 2 == 0)
{
//Debug.Log("==不在== 多边形内");
}
else
{
//Debug.Log("==在== 多边形内");
}
}
else
{
if ((bianX > x && listLeft.Count % 2 == 0) || (bianX < x && listRight.Count % 2 == 0))
{
//Debug.Log("=不在= 多边形内");
}
else
{
//Debug.Log("=在= 多边形内");
}
}


}


//判断点是否在多边形边上
public bool JudPointOnLine(float[,] dingdian, float[,] point, int bianshu)
{

for (int i = 0; i < bianshu - 1; i++)
{
//先判断是否在 边所在的直线上
if ((dingdian[i, 0] - point[0, 0]) * (dingdian[i + 1, 1] - point[0, 1]) - (dingdian[i + 1, 0] - point[0, 0]) * (dingdian[i, 1] - point[0, 1]) == 0)
{
//判断X值 与2个点X的值
if ((point[0, 0] > dingdian[i, 0] && point[0, 0] > dingdian[i + 1, 0]) || (point[0, 0] < dingdian[i, 0] && point[0, 0] < dingdian[i + 1, 0]))
{
return false;
}
else
{
return true;
}
}
}
//最后一边
if ((dingdian[bianshu - 1, 0] - point[0, 0]) * (dingdian[0, 1] - point[0, 1]) - (dingdian[0, 0] - point[0, 0]) * (dingdian[bianshu - 1, 1] - point[0, 1]) == 0)
{
//判断X值 与2个点X的值
if ((point[0, 0] > dingdian[bianshu - 1, 0] && point[0, 0] > dingdian[0, 0]) || (point[0, 0] < dingdian[bianshu - 1, 0] && point[0, 0] < dingdian[0, 0]))
{
return false;
}
else
{
return true;
}
}

return false;

}

//算法一
public void ForJudgePoint(float[,] dingdian, float[,] point)
{
int bianShu = dingdian.Length / 3;//三维向量 除以3 = 多边形边数
float[] results = new float[bianShu];
for (int i = 0; i < dingdian.Length / 3 - 1; i++)
{
//判断 多边形 第一个顶点到最后一个顶点 一共边数-1 条边(还剩最后顶点 到 第一个顶点 这条边)
//多边形 第一条边 的向量
float[,] polygonSide = { { dingdian[i, 0] - dingdian[i + 1, 0], dingdian[i, 1] - dingdian[i + 1, 1], dingdian[i, 2] - dingdian[i + 1, 2] } };
//多边形 第一条边向量的起始点 到 点point 的向量
float[,] pointToSide = { { dingdian[i, 0] - point[0, 0], dingdian[i, 1] - point[0, 1], dingdian[i, 2] - point[0, 2] } };
//二维向量叉乘 Z分量 = x1*y2-x2*y1
float res = polygonSide[0, 0] * pointToSide[0, 1] - pointToSide[0, 0] * polygonSide[0, 1];
res = res > 0 ? res = 1 : res = -1;
results[i] = res;
if (i >= 1)
{
if (results[i] != results[i - 1])
{
Debug.Log("点P ==不在== 多边形中!!!");
return;
}
}
}
//最后一条边
float[,] polygonLastSide = { { dingdian[bianShu - 1, 0] - dingdian[0, 0], dingdian[bianShu - 1, 1] - dingdian[0, 1], dingdian[bianShu - 1, 2] - dingdian[0, 2] } };
float[,] pointToLastSide = { { dingdian[bianShu - 1, 0] - point[0, 0], dingdian[bianShu - 1, 1] - point[0, 1], dingdian[bianShu - 1, 2] - point[0, 2] } };
float resLast = polygonLastSide[0, 0] * pointToLastSide[0, 1] - pointToLastSide[0, 0] * polygonLastSide[0, 1];
resLast = resLast > 0 ? resLast = 1 : resLast = -1;
if (resLast != results[0])
{
Debug.Log("点P ==不在== 多边形中!!!");
}
else
{
Debug.Log("点P ==在== 多边形中!!!");
}
}
}