136 lines
4.8 KiB
C#
136 lines
4.8 KiB
C#
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="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;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|