/// <summary>
        /// 相对原点的多边形边界
        /// </summary>
        /// <param name="source"></param>
        /// <param name="vertex"></param>
        /// <param name="mintheta"></param>
        /// <param name="maxtheta"></param>
        /// <param name="distance"></param>
        /// <returns></returns>
        public static bool getBoundPointIndex(Point source, List <Point> vertex, ref TriangleBound tb)
        {
            bool isEdge;
            int  startIndex = 0;

            //原点是否在多边形内部
            if (GeometricUtilities.PointInPolygon(vertex.ToArray(), source, out isEdge, ref startIndex))
            {
                return(false);
            }
            tb.maxIndex    = -1;
            tb.maxTheta    = -1;
            tb.minIndex    = int.MaxValue - 500;
            tb.minTheta    = 1000;
            tb.totalVertex = vertex.Count;
            double theta;

            Dictionary <int, Polar> tmp = new Dictionary <int, Polar>();
            int   cnt = vertex.Count;
            Polar p;

            //求相对原点的极坐标,根据theta角判断边界
            for (int i = 0; i < cnt; i++)
            {
                p     = GeometricUtilities.getPolarCoord(source, vertex[i]);
                theta = p.theta;
                tmp.Add(i, p);
                if (theta < tb.minTheta)
                {
                    tb.minIndex = i;
                    tb.minTheta = theta;
                }
                if (theta > tb.maxTheta)
                {
                    tb.maxIndex = i;
                    tb.maxTheta = theta;
                }
            }
            //说明多边形与x轴相交
            if (tb.maxTheta - tb.minTheta > Math.PI)
            {
                double th;
                tb.maxIndex = -1;
                tb.maxTheta = -1;
                tb.minIndex = int.MaxValue - 500;
                tb.minTheta = 1000;
                foreach (var kv in tmp)
                {
                    th = kv.Value.theta;
                    if (th < Math.PI)
                    {
                        if (th > tb.maxTheta)
                        {
                            tb.maxIndex = kv.Key;
                            tb.maxTheta = th;
                        }
                    }
                    else if (th < tb.minTheta)
                    {
                        tb.minIndex = kv.Key;
                        tb.minTheta = th;
                    }
                }
            }
            tb.stob = tmp[tb.minIndex].r > tmp[(tb.minIndex + 1) % cnt].r;
            return(true);
        }
        /// <summary>
        /// 获取一个建筑物棱边绕射点
        /// </summary>
        /// <param name="baseHeight"></param>
        /// <param name="tb"></param>
        /// <param name="gridLength"></param>
        /// <returns></returns>
        private static List <Point> getOneBuildingEdgePointsByShelter(double baseHeight, TriangleBound tb, double gridLength)
        {
            List <Point> ret = new List <Point>();

            Point        t;
            List <Point> v = buildingVertex[tb.buildingid];

            //获取垂直棱边
            for (int i = tb.minIndex, e = (tb.maxIndex + 1) % tb.totalVertex; i != e; i = (i + 1) % tb.totalVertex)
            {
                double d = gridLength / 2;
                for (double j = tb.baseHeight + d; j < tb.height - d; j += gridLength)
                {
                    t   = new Point(v[i]);
                    t.Z = j;
                    ret.Add(t);
                }
            }

            //获取水平棱边
            //for (int i = tb.minIndex, e = (tb.maxIndex + 1) % tb.totalVertex; i != e; i = (i + 1) % tb.totalVertex)
            //{
            //    List<Point> tmp = VerticalPlaneGrid.GetHEdgePoints(v[i], v[(i + 1) % tb.totalVertex], gridLength, tb.height);
            //    ret.AddRange(tmp);
            //}


            if (baseHeight > tb.height)
            {
                for (int i = 0; i < tb.totalVertex - 1; i++)
                {
                    List <Point> tmp = VerticalPlaneGrid.GetHEdgePoints(v[i], v[(i + 1) % tb.totalVertex], gridLength, tb.height);
                    ret.AddRange(tmp);
                }
            }
            else
            {
                int i = tb.minIndex, end = (tb.maxIndex + 1) % tb.totalVertex;
                int j = (i - 1 + tb.totalVertex) % tb.totalVertex;
                for (; i != end; j = i, i = (i + 1) % tb.totalVertex)
                {
                    List <Point> tmp = VerticalPlaneGrid.GetHEdgePoints(v[i], v[j], gridLength, tb.height);
                    ret.AddRange(tmp);
                }
            }
            return(ret);
        }
        /// <summary>
        /// 求比基准高度高的建筑物遮挡距离和角度范围
        /// </summary>
        /// <param name="source"></param>
        /// <param name="buildingids"></param>
        /// <param name="baseHeight"></param>
        /// <returns></returns>
        /// /// <summary>
        /// 建筑物遮挡关系(极坐标系)
        /// </summary>

        /*
         * public struct TriangleBound
         * {
         *  //建筑物id
         *  public int buildingid;
         *  public int totalVertex;
         *  //角度最小的边界点的索引
         *  public int minIndex;
         *  public double minTheta;
         *  //角度最大的边界点的索引
         *  public int maxIndex;
         *  public double maxTheta;
         *  //离原点较近的边是否是从minIndex到maxIndex
         *  public bool stob;
         *  //原点与建筑物的距离(近似值)
         *  public double distance;
         *  //违背遮挡高度
         *  public double baseHeight;
         *  //建筑物高度
         *  public double height;
         * }
         */
        public static List <TriangleBound> getShelterDisAndAngle(Point source, List <int> buildingids, double baseHeight)
        {
            Dictionary <int, TriangleBound> bdis = new Dictionary <int, TriangleBound>();

            TriangleBound tb = new TriangleBound();
            double        height, sz = baseHeight, altitude;
            int           bid;

            for (int i = 0, cnt = buildingids.Count; i < cnt; i++)
            {
                bid      = buildingids[i];
                height   = buildingHeight[bid];
                altitude = buildingAltitude[bid];  // 地形
                if (height > sz)
                {
                    tb            = new TriangleBound();
                    tb.height     = height;
                    tb.baseHeight = altitude; // 地形
                    tb.distance   = GeometricUtilities.GetDistanceOf2DPoints(source, buildingCenter[bid]);
                    bdis[bid]     = tb;
                }
            }

            List <KeyValuePair <int, TriangleBound> > bdisOrder = bdis.OrderBy(c => c.Value.distance).ToList();

            List <TriangleBound> ret = new List <TriangleBound>();

            foreach (var kv in bdisOrder)
            {
                bid = kv.Key;
                tb  = bdis[bid];

                // 得到每个建筑物相对于原点的最小、最大角度
                if (getBoundPointIndex(source, buildingVertex[bid], ref tb))
                {
                    tb.buildingid = bid;
                    ret.Add(tb);
                }
            }

            //去掉一些遮挡的
            double min1, max1, min2, max2;

            for (int i = ret.Count - 1; i > 0; i--)
            {
                for (int j = i - 1; j >= 0; j--)
                {
                    min1 = ret[j].minTheta;
                    max1 = ret[j].maxTheta;
                    min2 = ret[i].minTheta;
                    max2 = ret[i].maxTheta;

                    // j比i范围广,且在i前面
                    if (max2 < max1 && min2 > min1)
                    {
                        if (ret[j].height >= ret[i].height)  // j完全挡住了i
                        {
                            ret.RemoveAt(i);
                            break;
                        }
                        else if (ret[j].height > ret[i].baseHeight)                 // j部分遮住了i
                        {
                            TriangleBound tt = ret[i];                              // 更新i的可见度
                            tt.baseHeight = Math.Max(ret[j].height, tt.baseHeight); // 地形
                            ret[i]        = tt;
                        }
                    }
                }
            }

            return(ret);
        }