/// <summary> /// 构建当前缩放层级的瓦片 /// </summary> /// <param name="bound"></param> /// <param name="zoom"></param> void Build(GBound bound, int zoom) { int _tileSize = Projection.TileSize; //构建裁剪边界的矩形,用于整体裁剪 IGeometry _boundGeometry = bound.ToInsertPolygon(); //瓦片多尺度缓存 if (TileDictionary.ContainsKey(zoom)) { TileDictionary[zoom].Clear(); } else { TileDictionary[zoom] = new List <GTileElement>(); } //1.获取坐上右下坐标 Coordinate p0 = bound.Min; Coordinate p1 = bound.Max; //2.分尺度计算格网位置 //2.1 转换成尺度下的pixel Coordinate min = Projection.LatlngToPoint(p0, zoom); Coordinate max = Projection.LatlngToPoint(p1, zoom); //2.2 计算pixel下边界范围 GBound pixelBound = new GBound(new List <Coordinate>() { min, max }); //2.3 通过pixelbound计算range GBound range = new GBound(new List <Coordinate>() { new Coordinate((int)Math.Floor(pixelBound.Min.X / _tileSize), (int)Math.Floor(pixelBound.Min.Y / _tileSize)), new Coordinate((int)Math.Ceiling(pixelBound.Max.X / _tileSize) - 1, (int)Math.Ceiling(pixelBound.Max.Y / _tileSize) - 1), }); //2.3统计区域内瓦片的编号,边界经纬度等信息 for (int j = Convert.ToInt32(range.Min.Y); j <= Convert.ToInt32(range.Max.Y); j++) { for (int i = Convert.ToInt32(range.Min.X); i <= Convert.ToInt32(range.Max.X); i++) { //反算每块瓦片的边界经纬度 List <Coordinate> coordinates = new List <Coordinate>(); coordinates.Add(Projection.PointToLatLng(new Coordinate(i * 256, j * 256), zoom)); coordinates.Add(Projection.PointToLatLng(new Coordinate(i * 256 + 256, j * 256 + 256), zoom)); // GTileElement tile = new GTileElement() { X = i, Y = j, Z = zoom, Bound = new GBound(coordinates) }; TileDictionary[zoom].Add(tile); } } }
/// <summary> /// 构造函数 /// example var layer = new WebMercatorGridLayer() /// </summary> /// <param name="bound"></param> public VectorPyramid(GBound bound = null) { if (bound == null) { bound = new GBound(new List <Coordinate>() { new Coordinate(-180, 90), new Coordinate(180, -90) }); } for (int i = 0; i <= 19; i++) { Build(bound, i); } }
/// <summary> /// 给当前坐标编码 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="bound"></param> /// <returns></returns> private static byte Encode(double x, double y, GBound bound) { double xl = bound.Left, xr = bound.Right, yt = bound.Top, yb = bound.Bottom; byte c = 0; if (x < xl) { c |= LEFT; } if (x > xr) { c |= RIGHT; } if (y < yb) { c |= BOTTOM; } if (y > yt) { c |= TOP; } return(c); }
/// <summary> /// 裁剪线段 /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <param name="bound"></param> /// <returns></returns> private static List <Coordinate> ClipLine(Coordinate start, Coordinate end, GBound bound) { double xl = bound.Left, xr = bound.Right, yt = bound.Top, yb = bound.Bottom; // List <Coordinate> coords = new List <Coordinate>(); double x1 = start.X, y1 = start.Y, x2 = end.X, y2 = end.Y; byte code1 = Encode(x1, y1, bound); byte code2 = Encode(x2, y2, bound); byte code; double x = 0, y = 0; while (code1 != 0 || code2 != 0) { //1.线在窗口外,返回一个空数组 if ((code1 & code2) != 0) { return(coords); } code = code1; //找窗口外的点 if (code1 == 0) { code = code2; } //点在左边 if ((LEFT & code) != 0) { x = xl; y = y1 + (y2 - y1) * (xl - x1) / (x2 - x1); } //点在右边 else if ((RIGHT & code) != 0) { x = xr; y = y1 + (y2 - y1) * (xr - x1) / (x2 - x1); } //点在下面 else if ((BOTTOM & code) != 0) { y = yb; x = x1 + (x2 - x1) * (yb - y1) / (y2 - y1); } else if ((TOP & code) != 0) { y = yt; x = x1 + (x2 - x1) * (yt - y1) / (y2 - y1); } // if (code == code1) { x1 = x; y1 = y; code1 = Encode(x, y, bound); } else { x2 = x; y2 = y; code2 = Encode(x, y, bound); } } // coords.Add(new Coordinate(x1, y1)); coords.Add(new Coordinate(x2, y2)); return(coords); }
/// <summary> /// 裁剪线 /// </summary> /// <param name="subjectPolyline"></param> /// <param name="bound"></param> /// <returns></returns> public static List <Coordinate> GetIntersectedPolyline(Coordinate[] subjectPolyline, GBound bound) { List <Coordinate> clipLines = new List <Coordinate>(); for (int i = 0; i < subjectPolyline.Length - 1; i++) { Coordinate p0 = subjectPolyline[i]; Coordinate p1 = subjectPolyline[i + 1]; List <Coordinate> cliped = ClipLine(p0, p1, bound); clipLines.AddRange(cliped); } return(clipLines); }
public static List <Coordinate> GetIntersectedPolygon(Coordinate[] subjectPoly, GBound bound) { Coordinate[] clipPoly = bound.ToClipPolygon(); if (subjectPoly.Length < 3) { throw new ArgumentException(string.Format("The polygons passed in must have at least 3 points: subject={0}", subjectPoly.Length.ToString())); } List <Coordinate> outputList = subjectPoly.ToList(); // Make sure it's clockwise if (!IsClockwise(subjectPoly)) { outputList.Reverse(); } // Walk around the clip polygon clockwise foreach (Edge clipEdge in IterateEdgesClockwise(clipPoly)) { List <Coordinate> inputList = outputList.ToList(); // clone it outputList.Clear(); if (inputList.Count == 0) { // Sometimes when the polygons don't intersect, this list goes to zero. Jump out to avoid an index out of range exception break; } Coordinate S = inputList[inputList.Count - 1]; foreach (Coordinate E in inputList) { if (IsInside(clipEdge, E)) { if (!IsInside(clipEdge, S)) { Coordinate point = GetIntersect(S, E, clipEdge.From, clipEdge.To); outputList.Add(point); } outputList.Add(E); } else if (IsInside(clipEdge, S)) { Coordinate point = GetIntersect(S, E, clipEdge.From, clipEdge.To); outputList.Add(point); } S = E; } } // Exit Function return(outputList); }