经纬度帮助类

发布时间 2023-10-19 13:50:40作者: 码农阿亮

核心代码

/// <summary>
/// 点位信息
/// </summary>
[DataContract]
public class DPoint
{
    /// <summary>
    /// x坐标,对应经度
    /// </summary>
    public double x;

    /// <summary>
    /// y坐标,对应纬度
    /// </summary>
    public double y;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="lng">经度</param>
    /// <param name="lat">纬度</param>
    public DPoint(double lng, double lat)
    {
        x = lng;
        y = lat;
    }

    public DPoint()
    { }

    #region 已知两点计算距离

    private const double EARTH_RADIUS = 6378.137; //地球半径

    //private static double rad(double d)
    //{
    //    return d * Math.PI / 180.0;
    //}

    /// <summary>
    /// 将弧度转换为度
    /// </summary>
    /// <param name="radians">弧度</param>
    /// <returns>度</returns>
    private static double RadToDeg(double radians)
    {
        return radians * (180 / Math.PI);
    }

    /// <summary>
    /// 将度转换为弧度
    /// </summary>
    /// <param name="degrees">度</param>
    /// <returns>弧度</returns>
    private static double DegToRad(double degrees)
    {
        return degrees * (Math.PI / 180);
    }

    /// <summary>
    /// Calculates the middle point coordinate.
    /// </summary>
    /// <param name="firstCoordinate">The first coordinate.</param>
    /// <param name="secondCoordinate">The second coordinate.</param>
    /// <returns>Middle point coordinate</returns>
    public static DPoint GetMidPoint(DPoint firstCoordinate, DPoint secondCoordinate)
    {
        double lon1 = DegToRad(firstCoordinate.x);
        double lat1 = DegToRad(firstCoordinate.y);

        double lon2 = DegToRad(secondCoordinate.x);
        double lat2 = DegToRad(secondCoordinate.y);

        double deltaLong = lon2 - lon1;

        double Bx = Math.Cos(lat2) * Math.Cos(deltaLong);
        double By = Math.Cos(lat2) * Math.Sin(deltaLong);
        double lat3 = RadToDeg(Math.Atan2(Math.Sin(lat1) + Math.Sin(lat2), Math.Sqrt((Math.Cos(lat1) + Bx) * (Math.Cos(lat1) + Bx) + By * By)));
        double lon3 = RadToDeg(lon1 + Math.Atan2(By, Math.Cos(lat1) + Bx));

        return new DPoint(lon3, lat3);
    }

    /// <summary>
    /// 计算指定两点间的距离(单位KM)
    /// </summary>
    /// <param name="p1">起始点</param>
    /// <param name="p2">终止点</param>
    /// <returns>两点间的公里数</returns>
    public static double GetDistance(DPoint p1, DPoint p2)
    {
        return GetDistance(p1.y, p1.x, p2.y, p2.x);
    }

    /// <summary>
    /// 计算指定两点间的距离(单位KM)
    /// </summary>
    /// <param name="lat1">纬度1</param>
    /// <param name="lng1">经度1</param>
    /// <param name="lat2">纬度2</param>
    /// <param name="lng2">经度2</param>
    /// <returns>两点间距离公里数</returns>
    public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
    {
        double radLat1 = DegToRad(lat1);
        double radLat2 = DegToRad(lat2);
        double a = radLat1 - radLat2;
        double b = DegToRad(lng1) - DegToRad(lng2);

        double dst = 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)));
        dst = dst * EARTH_RADIUS;
        dst = Math.Round(dst * 10000) / 10000;
        return dst;
    }

    /// <summary>
    /// 计算指定两点间的距离(单位M)
    /// </summary>
    /// <param name="lat1">纬度1</param>
    /// <param name="lng1">经度1</param>
    /// <param name="lat2">纬度2</param>
    /// <param name="lng2">经度2</param>
    /// <returns>两点间距离公里数</returns>
    public static double GetDistanceMeter(double lat1, double lng1, double lat2, double lng2)
    {
        return GetDistance(lat1, lng1, lat2, lng2) * 1000;
    }

    /// <summary>
    /// 计算指定两点间的距离(单位M)
    /// </summary>
    /// <param name="lat1">纬度1</param>
    /// <param name="lng1">经度1</param>
    /// <param name="lat2">纬度2</param>
    /// <param name="lng2">经度2</param>
    /// <returns>两点间距离公里数</returns>
    public static double GetDistanceMeter(DPoint p1, DPoint p2)
    {
        return GetDistance(p1.y, p1.x, p2.y, p2.x) * 1000;
    }

    /// <summary>
    /// 判断点是否在多边形内或多边形上
    /// </summary>
    /// <param name="point">当前点</param>
    /// <param name="Points">多边形边界点集合</param>
    /// <returns></returns>
    public static bool IsPtInPoly(DPoint point, DPoint[] Points)
    {
        int iIndex;
        double dLon1 = 0, dLon2 = 0, dLat1 = 0, dLat2 = 0, dLon;
        if (Points.Length < 3)
        {
            return false;
        }
        var iSum = 0;
        var iCount = Points.Length;
        for (iIndex = 0; iIndex < iCount; iIndex++)
        {
            if (point.x == Points[iIndex].x && point.y == Points[iIndex].y)  //A点在多边形上    
                return true;

            if (iIndex == iCount - 1)
            {
                dLon1 = Points[iIndex].x;
                dLat1 = Points[iIndex].y;
                dLon2 = Points[0].x;
                dLat2 = Points[0].y;
            }
            else
            {
                dLon1 = Points[iIndex].x;
                dLat1 = Points[iIndex].y;
                dLon2 = Points[iIndex + 1].x;
                dLat2 = Points[iIndex + 1].y;
            }

            //以下语句判断A点是否在边的两端点的纬度之间,在则可能有交点
            if (((point.y > dLat1) && (point.y < dLat2)) || ((point.y > dLat2) && (point.y < dLat1)))
            {
                if (Math.Abs(dLat1 - dLat2) > 0)
                {
                    //获取A点向左射线与边的交点的x坐标:
                    dLon = dLon1 - ((dLon1 - dLon2) * (dLat1 - point.y)) / (dLat1 - dLat2);
                    //如果交点在A点左侧,则射线与边的全部交点数加一:
                    if (dLon < point.x)
                    {
                        iSum++;
                    }
                    //如果相等,则说明A点在边上
                    if (dLon == point.x)
                        return true;
                }
            }
        }
        if ((iSum % 2) != 0)
        {
            return true;
        }
        return false;
    }


    #endregion
}