转自https://blog.csdn.net/e_wsq/article/details/7536158,代码挺全的
可以判断某个点是否在区域内,用于区域管理
private void button1_Click(object sender, EventArgs e)
{
string[] _point = txt_lan.Text.Trim().Split(new char[] { ',' });
double lng = Convert.ToDouble(_point[0]);
double lat = Convert.ToDouble(_point[1]);
point point = new point(lng, lat);//要判断的坐标
if (listBox1.Items.Count > 0)
{
//区域坐标集
polygon = new point[listBox1.Items.Count];
for (int i = 0; i < listBox1.Items.Count; i++)
{
string[] temV = listBox1.Items[i].ToString().Trim().Split(new char[] { ',' });
polygon[i] = new point(double.Parse(temV[0]), double.Parse(temV[1]));
}
}
point ne = new point(0, 0), sw = new point(0, 0);
FindAppointDirection(polygon, ref ne, ref sw);//找东北 西南坐标
if (isPointInRect(ne, sw, point))
{
bool fuck = CalculationAlgorithm(polygon, point);
if (fuck)
{
label3.Text = "目标点在几何图形中";
}
else
{
label3.Text = "目标点不在几何图形中";
}
}
else
{
label3.Text = "目标点不在几何图形中";
}
}
#region
/// <summary>
/// 区域坐标集
/// </summary>
point[] polygon = new point[] {
new point(119.331244,26.036914),
new point(119.332699,26.037166),
new point(119.331675,26.035672),
new point(119.332843,26.035916),
new point(119.332861,26.036395)
};
public bool CalculationAlgorithm(point[] polygon, point p)
{
#region
point[] pts = polygon;//获取多边形点
//112.58464,26.909432
int N = pts.Length;
var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
var intersectCount = 0;//cross points count of x
var precision = 2e-10; //浮点类型计算时候与0比较时候的容差
point p1, p2;//neighbour bound vertices
p1 = pts[0];//left vertex
for (var i = 1; i <= N; ++i)
{//check all rays
if (p.Equals(p1))
{
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;
}
#endregion
}
/// <summary>
/// 判断点是否在矩形内
/// </summary>
/// <param name="ne"></param>
/// <param name="sw"></param>
/// <param name="Tagrtpoint"></param>
/// <returns></returns>
bool isPointInRect(point ne, point sw, point Tagrtpoint)
{
//西南脚点 point sw = new point(112.579325, 26.898023);
//东北 point ne = new point(26.915291, 112.608287);
return (Tagrtpoint.lng >= sw.lng && Tagrtpoint.lng <= ne.lng && Tagrtpoint.lat >= sw.lat && Tagrtpoint.lat <= ne.lat);
}
/// <summary>
/// 找东西南北经方向 简单说找东北 西南 坐标做一个矩形判断
/// </summary>
void FindAppointDirection(point[] polygon, ref point ne, ref point sw)
{
double[] iArrarylat = new double[polygon.Length];
double[] iArrarylng = new double[polygon.Length];
for (int i = 0; i < polygon.Length; i++)
{
iArrarylat[i] = polygon[i].lat;
iArrarylng[i] = polygon[i].lng;
}
Array.Sort(iArrarylat);
Array.Sort(iArrarylng);
ne.lat = iArrarylat[polygon.Length - 1];
ne.lng = iArrarylng[polygon.Length - 1];
sw.lat = iArrarylat[0];
sw.lng = iArrarylng[0];
}
public class point
{
public double lng;
public double lat;
public point(double lng, double lat)
{
this.lat = lat;
this.lng = lng;
}
}
/// <summary>
/// 判断点是否在多边形内.
/// ----------原理----------
/// 注意到如果从P作水平向左的射线的话,如果P在多边形内部,那么这条射线与多边形的交点必为奇数,
/// 如果P在多边形外部,则交点个数必为偶数(0也在内)。
/// </summary>
/// <param name="checkPoint">要判断的点</param>
/// <param name="polygonPoints">多边形的顶点</param>
/// <returns></returns>
public static bool IsInPolygon(PointF checkPoint, List<PointF> polygonPoints)
{
bool inside = false;
int pointCount = polygonPoints.Count;
PointF p1, p2;
for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)//第一个点和最后一个点作为第一条线,之后是第一个点和第二个点作为第二条线,之后是第二个点与第三个点,第三个点与第四个点...
{
p1 = polygonPoints[i];
p2 = polygonPoints[j];
if (checkPoint.Y < p2.Y)
{//p2在射线之上
if (p1.Y <= checkPoint.Y)
{//p1正好在射线中或者射线下方
if ((checkPoint.Y - p1.Y) * (p2.X - p1.X) > (checkPoint.X - p1.X) * (p2.Y - p1.Y))//斜率判断,在P1和P2之间且在P1P2右侧
{
//射线与多边形交点为奇数时则在多边形之内,若为偶数个交点时则在多边形之外。
//由于inside初始值为false,即交点数为零。所以当有第一个交点时,则必为奇数,则在内部,此时为inside=(!inside)
//所以当有第二个交点时,则必为偶数,则在外部,此时为inside=(!inside)
inside = (!inside);
}
}
}
else if (checkPoint.Y < p1.Y)
{
//p2正好在射线中或者在射线下方,p1在射线上
if ((checkPoint.Y - p1.Y) * (p2.X - p1.X) < (checkPoint.X - p1.X) * (p2.Y - p1.Y))//斜率判断,在P1和P2之间且在P1P2右侧
{
inside = (!inside);
}
}
}
return inside;
}
#endregion
#region 求两点坐标间的距离
private void button4_Click(object sender, EventArgs e)
{
string[] tmV = txt_Point1.Text.Trim().Split(new char[] { ',' });
string[] tmV2 = txt_Point2.Text.Trim().Split(new char[] { ',' });
double _JL = GetDistance(double.Parse(tmV[1]), double.Parse(tmV[0]), double.Parse(tmV2[1]), double.Parse(tmV2[0]));
txt_JL.Text = _JL.ToString();
}
//地球半径,单位米
private const double EARTH_RADIUS = 6378137;
/// <summary>
/// 计算两点位置的距离,返回两点的距离,单位:米
/// 该公式为GOOGLE提供,误差小于0.2米
/// </summary>
/// <param name="lng1">第一点经度</param>
/// <param name="lat1">第一点纬度</param>
/// <param name="lng2">第二点经度</param>
/// <param name="lat2">第二点纬度</param>
/// <returns></returns>
public double GetDistance(double lng1, double lat1, double lng2, double lat2)
{
double radLat1 = Rad(lat1);
double radLng1 = Rad(lng1);
double radLat2 = Rad(lat2);
double radLng2 = Rad(lng2);
double a = radLat1 - radLat2;
double b = radLng1 - radLng2;
double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))) * EARTH_RADIUS;
return result;
}
/// <summary>
/// 经纬度转化成弧度
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
private double Rad(double d)
{
return (double)d * Math.PI / 180d;
}
#endregion