SGGL_HBAZ/SGGL/SgManager.AI/GpsPolygonHelper.cs

163 lines
5.8 KiB
C#
Raw Normal View History

2025-02-12 09:27:47 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SgManager.AI
{
public class Gpslocation
{
public double lat;
public double lng;
}
public class GpsPolygonHelper
{/// <summary>
/// 判断当前位置是否在不规则形状里面
/// </summary>
/// <param name="nvert">不规则形状的定点数</param>
/// <param name="vertx">当前x坐标</param>
/// <param name="verty">当前y坐标</param>
/// <param name="testx">不规则形状x坐标集合</param>
/// <param name="testy">不规则形状y坐标集合</param>
/// <returns></returns>
public static bool PositionPnpoly(int nvert, List<double> vertx, List<double> verty, double testx, double testy)
{
int i, j, c = 0;
for (i = 0, j = nvert - 1; i < nvert; j = i++)
{
if (((verty[i] > testy) != (verty[j] > testy)) && (testx < (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + vertx[i]))
{
c = 1 + c; ;
}
}
if (c % 2 == 0)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 坐标点是否在多边形内判断
/// </summary>
/// <param name="point"></param>
/// <param name="pts"></param>
/// <returns></returns>
public static bool isPointInPolygon(Gpslocation point, List<Gpslocation> pts)
{
//检查类型
if (point == null || pts == null)
return false;
var N = pts.Count;
var boundOrVertex = true; //如果点位于多边形的顶点或边上也算做点在多边形内直接返回true
var intersectCount = 0; //cross points count of x
var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
Gpslocation p1, p2; //neighbour bound vertices
var p = point; //测试点
p1 = pts[0]; //left vertex
for (var i = 1; i <= N; ++i)
{
//check all rays
if (p.lat.Equals(p1.lat) && p.lng.Equals(p1.lng))
{
return boundOrVertex; //p is an vertex
}
p2 = pts[i % N]; //right vertex
if (p.lat < Math.Min(p1.lat, p2.lat) || p.lat > Math.Max(p1.lat, p2.lat))
{
//ray is outside of our interests
p1 = p2;
continue; //next ray left point
}
if (p.lat > Math.Min(p1.lat, p2.lat) && p.lat < Math.Max(p1.lat, p2.lat))
{
//ray is crossing over by the algorithm (common part of)
if (p.lng <= Math.Max(p1.lng, p2.lng))
{
//x is before of ray
if (p1.lat == p2.lat && p.lng >= Math.Min(p1.lng, p2.lng))
{
//overlies on a horizontal ray
return boundOrVertex;
}
if (p1.lng == p2.lng)
{
//ray is vertical
if (p1.lng == p.lng)
{
//overlies on a vertical ray
return boundOrVertex;
}
else
{
//before ray
++intersectCount;
}
}
else
{
//cross point on the left side
var xinters =
(p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) +
p1.lng; //cross point of lng
if (Math.Abs(p.lng - xinters) < precision)
{
//overlies on a ray
return boundOrVertex;
}
if (p.lng < xinters)
{
//before ray
++intersectCount;
}
}
}
}
else
{
//special case when ray is crossing through the vertex
if (p.lat == p2.lat && p.lng <= p2.lng)
{
//p crossing over p2
var p3 = pts[(i + 1) % N]; //next vertex
if (p.lat >= Math.Min(p1.lat, p3.lat) && p.lat <= Math.Max(p1.lat, p3.lat))
{
//p.lat lies between p1.lat & p3.lat
++intersectCount;
}
else
{
intersectCount += 2;
}
}
}
p1 = p2; //next ray left point
}
if (intersectCount % 2 == 0)
{
//偶数在多边形外
return false;
}
else
{
//奇数在多边形内
return true;
}
}
}
}