原理:
奇偶规则射线法:多边形内任意一点,向任意方向射线,相交数必然为奇数。
接着我们就可以利用线段到线段的相交数,求出想要的结果。
cs
using System.Collections.Generic;
using System;
using UnityEngine;
using System.Drawing;
public class TestTools : MonoBehaviour
{
public List<Transform> tranPos = new List<Transform>();
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
Point GetNode(Transform _t)
{
var _nod = new Point(_t.position.x, _t.position.z);
return _nod;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.A)) IsIn();
}
void IsIn()
{
var polygon = new List<Point>();
polygon.Add(GetNode(tranPos[0]));
polygon.Add(GetNode(tranPos[1]));
polygon.Add(GetNode(tranPos[2]));
polygon.Add(GetNode(tranPos[3]));
Point point = GetNode(tranPos[4]);
Point _pEnd = new Point(100,point.Y) ;
int _num = 0;//相交数量
for (var _i = 0; _i < polygon.Count; _i++)
{
var _p1 = polygon[_i];
Point _p2 = polygon[0];
if (_i < polygon.Count - 1) _p2 = polygon[_i + 1];
Debug.Log("~~~~~~~~!!!");
Debug.Log(_p1.X + " " + _p1.Y + " " + _p2.X + " " + _p2.Y);
var intersect = AreSegmentsIntersecting(point, _pEnd, _p1, _p2);
Debug.Log(intersect);
if (intersect) _num++;
}
Debug.LogError("相交数" + _num);
var _get = _num % 2 != 0;
Debug.Log(_get ? "在多边形内" : "不在多边形内");
}
// 定义点结构
public struct Point
{
public double X, Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
// 计算两个向量的叉积 (P2 - P1) × (P3 - P1)
private static double CrossProduct(Point p1, Point p2, Point p3)
{
return (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
}
// 判断点p是否在a和b之间(用于共线情况下判断是否有重叠)
private static bool IsPointOnSegment(Point p, Point a, Point b)
{
return Math.Min(a.X, b.X) <= p.X && p.X <= Math.Max(a.X, b.X) &&
Math.Min(a.Y, b.Y) <= p.Y && p.Y <= Math.Max(a.Y, b.Y);
}
// 判断两条线段 (p1, p2) 和 (p3, p4) 是否相交
public static bool AreSegmentsIntersecting(Point p1, Point p2, Point p3, Point p4)
{
double d1 = CrossProduct(p3, p4, p1);
double d2 = CrossProduct(p3, p4, p2);
double d3 = CrossProduct(p1, p2, p3);
double d4 = CrossProduct(p1, p2, p4);
// 检查叉积是否满足线段相交条件
if (d1 * d2 < 0 && d3 * d4 < 0)
{
return true;
}
// 检查是否共线且重叠
if (d1 == 0 && IsPointOnSegment(p1, p3, p4)) return true;
if (d2 == 0 && IsPointOnSegment(p2, p3, p4)) return true;
if (d3 == 0 && IsPointOnSegment(p3, p1, p2)) return true;
if (d4 == 0 && IsPointOnSegment(p4, p1, p2)) return true;
return false;
}
public static void Main()
{
Point p1 = new Point(0, 0);
Point p2 = new Point(2, 2);
Point p3 = new Point(0, 2);
Point p4 = new Point(2, 0);
bool intersecting = AreSegmentsIntersecting(p1, p2, p3, p4);
Console.WriteLine("Are the segments intersecting? " + (intersecting ? "Yes" : "No"));
}
}
简化函数为:
cs
public bool IsInPolygon(Point _p, List<Point> _polygon)
{
// 计算两个向量的叉积 (P2 - P1) × (P3 - P1)
double CrossProduct(Point p1, Point p2, Point p3)
{
return (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
}
// 判断点p是否在a和b之间(用于共线情况下判断是否有重叠)
bool IsPointOnSegment(Point p, Point a, Point b)
{
return Math.Min(a.X, b.X) <= p.X && p.X <= Math.Max(a.X, b.X) &&
Math.Min(a.Y, b.Y) <= p.Y && p.Y <= Math.Max(a.Y, b.Y);
}
// 判断两条线段 (p1, p2) 和 (p3, p4) 是否相交
bool AreSegmentsIntersecting(Point p1, Point p2, Point p3, Point p4)
{
double d1 = CrossProduct(p3, p4, p1);
double d2 = CrossProduct(p3, p4, p2);
double d3 = CrossProduct(p1, p2, p3);
double d4 = CrossProduct(p1, p2, p4);
// 检查叉积是否满足线段相交条件
if (d1 * d2 < 0 && d3 * d4 < 0)
{
return true;
}
// 检查是否共线且重叠
if (d1 == 0 && IsPointOnSegment(p1, p3, p4)) return true;
if (d2 == 0 && IsPointOnSegment(p2, p3, p4)) return true;
if (d3 == 0 && IsPointOnSegment(p3, p1, p2)) return true;
if (d4 == 0 && IsPointOnSegment(p4, p1, p2)) return true;
return false;
}
Point _pEnd = new Point(float.MaxValue, _p.Y);
int _num = 0;//相交数量
for (var _i = 0; _i < _polygon.Count; _i++)
{
var _p1 = _polygon[_i];
Point _p2 = _polygon[0];
if (_i < _polygon.Count - 1) _p2 = _polygon[_i + 1];
Debug.Log("~~~~~~~~!!!");
Debug.Log(_p1.X + " " + _p1.Y + " " + _p2.X + " " + _p2.Y);
var intersect = AreSegmentsIntersecting(_p, _pEnd, _p1, _p2);
Debug.Log(intersect);
if (intersect) _num++;
}
Debug.LogError("相交数" + _num);
var _get = _num % 2 != 0;
Debug.Log(_get ? "在多边形内" : "不在多边形内");
return _get;
}
// 定义点结构
public struct Point
{
public double X, Y;
public Point(double x, double y)
{
X = x;
Y = y;
}
}
除了顶点照顾不到,基本也够用了。