163 lines
5.8 KiB
C#
163 lines
5.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="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;
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|