Exemple #1
0
        /// <summary>
        /// 判断点在围栏内(暴力遍历法)
        /// <para>
        /// 计算原理
        /// </para>
        /// <para>
        /// 地理围栏一般是多边形,判断点在多边形内部可以通过射线法来判断点是否在多边形内部。从一点出发沿着X轴画一条射线,依次判断该射线与每条边的交点,并统计交点个数,如果交点数为奇数,则在多边形内部,如果焦点数是偶数,则在外部,射线法对凸和非凸多边形都适用,复杂度为O(N),其它N是边数。
        /// 当地理围栏多边形数目较少时,我们可以依次遍历每一个多边形(暴力遍历法),然后用射线法进行判断,这样效率也很高。而当多边形数目较多时,比如有10万个多边形,这个时候需要执行10万次射线法,响应时间达到3.9秒。
        /// </para>
        /// </summary>
        /// <param name="point"></param>
        /// <param name="pointRange"></param>
        /// <returns></returns>
        private static bool isPointInPolygon(Util.LBS.LBSPoint point, List <Util.LBS.LBSPoint> pointRange)
        {
            int    iSum = 0, iCount;
            double dLng1, dLng2, dLat1, dLat2, dLng;
            double ALat = point.Lat;
            double ALon = point.Lng;

            if (pointRange.Count < 3)
            {
                return(false);
            }

            iCount = pointRange.Count;

            for (int i = 0; i < iCount; i++)
            {
                if (i == iCount - 1)
                {
                    dLng1 = pointRange[i].Lng;
                    dLat1 = pointRange[i].Lat;
                    dLng2 = pointRange[0].Lng;
                    dLat2 = pointRange[0].Lat;
                }
                else
                {
                    dLng1 = pointRange[i].Lng;
                    dLat1 = pointRange[i].Lat;
                    dLng2 = pointRange[i + 1].Lng;
                    dLat2 = pointRange[i + 1].Lat;
                }

                //以下语句判断A点是否在边的两端点的水平平行线之间,在则可能有交点,开始判断交点是否在左射线上
                if (((ALat >= dLat1) && (ALat < dLat2)) || ((ALat >= dLat2) && (ALat < dLat1)))
                {
                    if (Math.Abs(dLat1 - dLat2) > 0)
                    {
                        //得到 A点向左射线与边的交点的x坐标:
                        dLng = dLng1 - ((dLng1 - dLng2) * (dLat1 - ALat)) / (dLat1 - dLat2);

                        // 如果交点在A点左侧(说明是做射线与 边的交点),则射线与边的全部交点数加一:
                        if (dLng < ALon)
                        {
                            iSum++;
                        }
                    }
                }
            }

            if (iSum % 2 != 0)
            {
                return(true);
            }

            return(false);
        }
Exemple #2
0
        /// <summary>
        /// 最小外包法
        /// </summary>
        /// <param name="point"></param>
        /// <param name="pointRange"></param>
        /// <returns></returns>
        private static bool isSimpleMatch(Util.LBS.LBSPoint point, List <Util.LBS.LBSPoint> pointRange)
        {
            double max_lng = pointRange.Max(x => x.Lng);
            double max_lat = pointRange.Max(x => x.Lat);

            double min_lon = pointRange.Min(x => x.Lng);
            double min_lat = pointRange.Min(x => x.Lat);

            double aLng = point.Lng;
            double aLat = point.Lat;

            if (aLng >= max_lng || aLng <= min_lon || aLat >= max_lat || aLat <= min_lat)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
Exemple #3
0
        /// <summary>
        /// 围栏计算(点是否在围栏内)
        /// </summary>
        /// <param name="latlon">单点坐标</param>
        /// <param name="APoints">坐标集合</param>
        /// <returns></returns>
        public static bool MBR(Util.LBS.LBSPoint point, List <Util.LBS.LBSPoint> pointRange)
        {
            if (pointRange == null || pointRange.Count < 3)
            {
                throw new ArgumentException("集合 pointRange 的长度不足3, 无法计算");
            }

            if (false == (pointRange.Count == pointRange.Where(i => i.LocationType == point.LocationType).Count()))
            {
                throw new ArgumentException("传入参数的属性 LocationType 不一致");
            }

            if (isSimpleMatch(point, pointRange)) // 先用最小外包法判断
            {
                // 符合最小外包法判断后用暴力遍历法细致判断
                return(isPointInPolygon(point, pointRange));
            }
            else
            {
                return(false);
            }
        }