【项目记录】-路灯光照分析系统 gmap.net

需求

2016年5月,客户要求在地图上显示路灯及数据,分析数据生成报表,以便查看分析路灯情况。

选型

国外项目就不考虑国内的地图了,开始想使用google的web地图,考虑到地图上标记物过多影响性能及使用体验,对gmap测试后,选用gmap.net。

开发

功能:

1.导入路灯及数据,在地图上添加、编辑、删除路灯,路灯数据软件修正、移除错误数据
2.地图上线时路灯及数据,数据以标记、曲线、表格方式显示
3.导出整个系统数据,下次可以将系统导出的文件导入进行查看;导出生成excel报表
4.多点测距;多边形方式进行选择查看,选择多边形内路灯情况

代码

计算2个坐标点距离

    private static double EARTH_RADIUS = 6378137;//赤道半径(单位m)  
    /** 
     * 转化为弧度(rad) 
     * */
    private static double rad(double d)
    {
        return d * Math.PI / 180.0;
    }

    /** 
     * 基于余弦定理求两经纬度距离 
     * @param lon1 第一点的精度 
     * @param lat1 第一点的纬度 
     * @param lon2 第二点的精度 
     * @param lat3 第二点的纬度 
     * @return 返回的距离,单位m 
     * */
    public static double GetDistance(double lng1, double lat1, double lng2, double lat2)
    {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);

        double radLng1 = rad(lng1);
        double radLng2 = rad(lng2);

        if (radLat1 < 0)
            radLat1 = Math.PI / 2 + Math.Abs(radLat1);// south  
        if (radLat1 > 0)
            radLat1 = Math.PI / 2 - Math.Abs(radLat1);// north  
        if (radLng1 < 0)
            radLng1 = Math.PI * 2 - Math.Abs(radLng1);// west  
        if (radLat2 < 0)
            radLat2 = Math.PI / 2 + Math.Abs(radLat2);// south  
        if (radLat2 > 0)
            radLat2 = Math.PI / 2 - Math.Abs(radLat2);// north  
        if (radLng2 < 0)
            radLng2 = Math.PI * 2 - Math.Abs(radLng2);// west  
        double x1 = EARTH_RADIUS * Math.Cos(radLng1) * Math.Sin(radLat1);
        double y1 = EARTH_RADIUS * Math.Sin(radLng1) * Math.Sin(radLat1);
        double z1 = EARTH_RADIUS * Math.Cos(radLat1);

        double x2 = EARTH_RADIUS * Math.Cos(radLng2) * Math.Sin(radLat2);
        double y2 = EARTH_RADIUS * Math.Sin(radLng2) * Math.Sin(radLat2);
        double z2 = EARTH_RADIUS * Math.Cos(radLat2);

        double d = Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));
        //余弦定理求夹角  
        double theta = Math.Acos((EARTH_RADIUS * EARTH_RADIUS + EARTH_RADIUS * EARTH_RADIUS - d * d) / (2 * EARTH_RADIUS * EARTH_RADIUS));
        double dist = theta * EARTH_RADIUS;
        return dist;
    }

获取方向角度

    /// <summary>
    /// 获取方向角度
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double GetDirection(double lon1, double lat1, double lon2, double lat2)
    {
        double x1 = lon1;
        double y1 = lat1;
        double x2 = lon2;
        double y2 = lat2;
        double pi = Math.PI;
        double w1 = y1 / 180 * pi;
        double j1 = x1 / 180 * pi;
        double w2 = y2 / 180 * pi;
        double j2 = x2 / 180 * pi;
        double ret;
        if (j1 == j2)
        {
            if (w1 > w2) ret = 270; //北半球的情况,南半球忽略
            else if (w1 < w2) ret = 90;
            else ret =-1;//位置完全相同
        }
        ret = 4 * Math.Pow(Math.Sin((w1 - w2) / 2), 2) - Math.Pow(Math.Sin((j1 - j2) / 2) * (Math.Cos(w1) - Math.Cos(w2)), 2);
        ret = Math.Sqrt(ret);
        double temp = (Math.Sin(Math.Abs(j1 - j2) / 2) * (Math.Cos(w1) + Math.Cos(w2)));
        ret = ret / temp;
        ret = Math.Atan(ret) / pi * 180;
        if (j1 > j2) // 1为参考点坐标
        {
            if (w1 > w2) ret += 180;
            else ret = 180 - ret;
        }
        else if (w1 > w2) ret = 360 - ret;

        return ret;
        //result.Text = Convert.ToString(ret);

        //if ((ret <= 10) || (ret > 350)) angle.Text = "东";
        //if ((ret > 10) && (ret <= 80)) angle.Text = "东北";
        //if ((ret > 80) && (ret <= 100)) angle.Text = "北";
        //if ((ret > 100) && (ret <= 170)) angle.Text = "西北";
        //if ((ret > 170) && (ret <= 190)) angle.Text = "西";
        //if ((ret > 190) && (ret <= 260)) angle.Text = "西南";
        //if ((ret > 260) && (ret <= 280)) angle.Text = "南";
        //if ((ret > 280) && (ret <= 350)) angle.Text = "东南";
    }

判断坐标是否在多边形内

    /// <summary>
    /// 判断点是否在多边形内.
    /// </summary>
    /// <param name="checkPoint">要判断的点</param>
    /// <param name="polygonPoints">多边形的顶点</param>
    /// <returns></returns>
    public static bool IsInPolygon(PointLatLng checkPoint, List<PointLatLng> polygonPoints)
    {
        int counter = 0;
        int i;
        double xinters;
        PointLatLng p1, p2;
        int pointCount = polygonPoints.Count;
        p1 = polygonPoints[0];
        for (i = 1; i <= pointCount; i++)
        {
            p2 = polygonPoints[i % pointCount];
            if (checkPoint.Lat > Math.Min(p1.Lat, p2.Lat)//校验点的Y大于线段端点的最小Y
                && checkPoint.Lat <= Math.Max(p1.Lat, p2.Lat))//校验点的Y小于线段端点的最大Y
            {
                if (checkPoint.Lng <= Math.Max(p1.Lng, p2.Lng))//校验点的X小于等线段端点的最大X(使用校验点的左射线判断).
                {
                    if (p1.Lat != p2.Lat)//线段不平行于X轴
                    {
                        xinters = (checkPoint.Lat - p1.Lat) * (p2.Lng - p1.Lng) / (p2.Lat - p1.Lat) + p1.Lng;
                        if (p1.Lng == p2.Lng || checkPoint.Lng <= xinters)
                        {
                            counter++;
                        }
                    }
                }

            }
            p1 = p2;
        }

        if (counter % 2 == 0)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

多点测距

多边形选择

关于测距

测距尝试过使用gmap提供的根据道路测距,发现还是不太准,所以还是选择了手动选择坐标点连线测距。

后记

该项目2018年初还增加了一些功能,开发过程中有不少次沟通和修改,主要就是一些gps和数据拆分、补全上的处理和报表算法上有些繁琐,项目目前暂时告一段落。

posted @ 2018-02-27 14:51  -echo  阅读(1519)  评论(0编辑  收藏  举报
AmazingCounters.com次访问