├── .DS_Store ├── demo ├── 1.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png ├── App.config ├── Program.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs └── Resources.resx ├── WMSListener.cs ├── Shp读取与成图 ├── PointFeature.cs ├── PolygonFeature.cs ├── PolylineFeature.cs ├── Shapefile.cs └── FeatureClass.cs ├── WMS.cs ├── CapabilityRequest.cs ├── WMSServer.csproj ├── MapRequest.cs ├── WMSThreadHandler.cs ├── README.md └── capability.xml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/.DS_Store -------------------------------------------------------------------------------- /demo/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/1.png -------------------------------------------------------------------------------- /demo/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/2.png -------------------------------------------------------------------------------- /demo/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/3.png -------------------------------------------------------------------------------- /demo/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/4.png -------------------------------------------------------------------------------- /demo/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/5.png -------------------------------------------------------------------------------- /demo/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/6.png -------------------------------------------------------------------------------- /demo/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/7.png -------------------------------------------------------------------------------- /demo/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/8.png -------------------------------------------------------------------------------- /demo/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhengyuan-liu/WMS-Server/HEAD/demo/9.png -------------------------------------------------------------------------------- /App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WMSServer 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | WMSListener WMSServer = new WMSListener(); 14 | WMSServer.Start(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("WMSServer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WMSServer")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("fe83ce81-14fa-43d1-a116-33f80898c827")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WMSListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace WMSServer 11 | { 12 | class WMSListener 13 | { 14 | private TcpListener myTcpListener; 15 | 16 | public WMSListener() 17 | { 18 | myTcpListener = new TcpListener(IPAddress.Any, 8080); 19 | } 20 | 21 | public void Start() 22 | { 23 | myTcpListener.Start(); 24 | Console.WriteLine("WMS Server started. press ctrl+C to stop\n"); 25 | while (true) 26 | { 27 | while (!myTcpListener.Pending()) ; 28 | WMSThreadHandler myWorker = new WMSThreadHandler(this.myTcpListener); 29 | Thread myWorkerthread = new Thread(new ThreadStart(myWorker.HandleThread)); 30 | myWorkerthread.Name = "Created at" + DateTime.Now.ToString(); 31 | myWorkerthread.Start(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Shp读取与成图/PointFeature.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Drawing; 7 | 8 | namespace shp读取 9 | { 10 | struct PointD 11 | { 12 | double x, y; 13 | 14 | public PointD(double x0,double y0) 15 | { 16 | this.x = x0; 17 | this.y = y0; 18 | } 19 | 20 | public double X 21 | { 22 | get { return this.x; } 23 | } 24 | 25 | public double Y 26 | { 27 | get { return this.y; } 28 | } 29 | } 30 | 31 | class PointFeature 32 | { 33 | static ShapeTypes shapeType = ShapeTypes.Point; 34 | static int shapeTypeID = 1; 35 | double x; 36 | double y; 37 | 38 | public PointFeature(double x0,double y0) 39 | { 40 | this.x = x0; 41 | this.y = y0; 42 | } 43 | 44 | public Point GetBMPPoint(BBOX boundarybox, int width, int height) 45 | { 46 | double x = width * (this.x - boundarybox.xmin) / (boundarybox.xmax - boundarybox.xmin); 47 | double y = height * (this.y - boundarybox.ymin) / (boundarybox.ymax - boundarybox.ymin); 48 | Point bmpPoint = new Point((int)x, height - (int)y); 49 | return bmpPoint; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WMS.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.Drawing; 8 | using shp读取; 9 | 10 | namespace WMSServer 11 | { 12 | class WMSExpection : Exception 13 | { 14 | public WMSExpection() { } 15 | public WMSExpection(string message) : base(message) { } 16 | public WMSExpection(string message, Exception inner) : base(message, inner) { } 17 | } 18 | 19 | class WMS 20 | { 21 | public static Byte[] GetMap(MapRequest mapReq) 22 | { 23 | string filepath = @"D:\MyDocuments\pkumap\"; 24 | Bitmap tempbmp = new Bitmap(mapReq.Width, mapReq.Height); 25 | for (int i = 0; i < mapReq.layers.Length; i++) 26 | { 27 | string filename = filepath + mapReq.layers[i] + ".shp"; 28 | Shapefile shp = new Shapefile(filename); 29 | FeatureClass fc = shp.GetFeature(); 30 | tempbmp = fc.DrawBMP(mapReq.bbox, tempbmp, mapReq.styles[0]); 31 | } 32 | 33 | MemoryStream ms = new MemoryStream(); 34 | tempbmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png); 35 | byte[] bitmapData = new Byte[ms.Length]; 36 | bitmapData = ms.ToArray(); 37 | return bitmapData; 38 | } 39 | 40 | public static Byte[] GetCapabilityData(CapabilityRequest req) 41 | { 42 | return Encoding.UTF8.GetBytes(WMSServer.Properties.Resources.capability); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CapabilityRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace WMSServer 9 | { 10 | class CapabilityRequest 11 | { 12 | private string service = "WMS"; 13 | private string request = "GetCapabilities"; 14 | private string[] Versions = null; 15 | private string updataSequence = ""; 16 | private string[] acceptFormats = null; 17 | private string requestData; 18 | 19 | public CapabilityRequest(string requestData) 20 | { 21 | Console.WriteLine(requestData); 22 | string temp = Regex.Match(requestData.Split('\n')[0], @"/.+?HTTP").Value; 23 | Console.WriteLine(temp); 24 | string paras = temp.Substring(1, temp.Length - 5); 25 | SetPara(paras); 26 | } 27 | 28 | private void SetPara(string paras) 29 | { 30 | try 31 | { 32 | string[] msgs = paras.Split(@"&?".ToArray(), StringSplitOptions.RemoveEmptyEntries); 33 | int i = 0, n = msgs.Length; 34 | for (i = 1; i < n; i++) 35 | SetParameter(msgs[i]); 36 | } 37 | catch (Exception ex) 38 | { 39 | throw ex; 40 | } 41 | } 42 | 43 | public void SetParameter(string msg) 44 | { 45 | try 46 | { 47 | string[] paras = msg.Split("= ".ToArray(), StringSplitOptions.RemoveEmptyEntries); 48 | if (paras[0] == "Version") 49 | paras.CopyTo(Versions, 1); 50 | else if (paras[0] == "updateSequence") 51 | updataSequence = paras[1]; 52 | else if (paras[0] == "Format") 53 | paras.CopyTo(acceptFormats, 1); 54 | } 55 | catch (Exception) 56 | { 57 | throw new WMSExpection("操作请求包含无效参数值"); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Shp读取与成图/PolygonFeature.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.Drawing; 8 | 9 | namespace shp读取 10 | { 11 | class PolygonFeature 12 | { 13 | BBOX bbox; 14 | int numParts; // 当前面目标所包含的子环的个数 15 | int numPoints; // 构成当前面状目标的所有顶点的个数 16 | int[] parts; // 每个子环的第一个坐标点在 Points 的位置 17 | PointD[] points; // 记录所有坐标点的数组 18 | int byteCount = 0; 19 | 20 | public PolygonFeature(BinaryReader br) 21 | { 22 | int recordNumber; 23 | int contentLength; //坐标记录长度 24 | int shapeType; //几何类型 25 | 26 | //读取记录头 27 | recordNumber = Shapefile.ReverseByte(br.ReadInt32()); 28 | contentLength = Shapefile.ReverseByte(br.ReadInt32()); 29 | byteCount += 8; 30 | //读取记录内容 31 | shapeType = br.ReadInt32(); 32 | bbox.xmin = br.ReadDouble(); 33 | bbox.ymin = br.ReadDouble(); 34 | bbox.xmax = br.ReadDouble(); 35 | bbox.ymax = br.ReadDouble(); 36 | numParts = br.ReadInt32(); 37 | numPoints = br.ReadInt32(); 38 | byteCount += 44; 39 | parts = new int[numParts]; 40 | for (int i = 0; i < numParts; i++) 41 | parts[i] = br.ReadInt32(); 42 | byteCount += 4 * numParts; 43 | points = new PointD[numPoints]; 44 | double x, y; 45 | for (int i = 0; i < numPoints; i++) 46 | { 47 | x = br.ReadDouble(); 48 | y = br.ReadDouble(); 49 | points[i] = new PointD(x, y); 50 | } 51 | byteCount += 16 * numPoints; 52 | } 53 | 54 | /// 55 | /// 字节数 56 | /// 57 | public int ByteCount 58 | { 59 | get { return this.byteCount; } 60 | } 61 | 62 | public Point[] GetBMPPoints(BBOX boundarybox, int width, int height) 63 | { 64 | Point[] bmpPoints = new Point[numPoints]; 65 | for (int i = 0; i < numPoints; i++) 66 | { 67 | double x = width * (points[i].X - boundarybox.xmin) / (boundarybox.xmax - boundarybox.xmin); 68 | double y = height * (points[i].Y - boundarybox.ymin) / (boundarybox.ymax - boundarybox.ymin); 69 | bmpPoints[i] = new Point((int)x, height - (int)y); 70 | } 71 | return bmpPoints; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Shp读取与成图/PolylineFeature.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.Drawing; 8 | 9 | namespace shp读取 10 | { 11 | class PolylineFeature 12 | { 13 | static ShapeTypes shapeType = ShapeTypes.Polyline; 14 | static int shapeTypeID = 3; 15 | BBOX bbox; // 当前线状目标的坐标范围 16 | int numParts; // 当前线目标所包含的子线段的个数 17 | int numPoints; // 当前线目标所包含的顶点个数 18 | public int[] parts; // 每个子线段的第一个坐标点在 Points 的位置 19 | PointD[] points; // 记录所有坐标点的数组 20 | int length = 0; 21 | 22 | public PolylineFeature(BinaryReader br) 23 | { 24 | int recordNumber; 25 | int contentLength; //坐标记录长度 26 | int shapeType; //几何类型 27 | 28 | //读取记录头 29 | recordNumber = Shapefile.ReverseByte(br.ReadInt32()); 30 | contentLength = Shapefile.ReverseByte(br.ReadInt32()); 31 | length += 8; 32 | //读取记录内容 33 | shapeType = br.ReadInt32(); 34 | bbox.xmin = br.ReadDouble(); 35 | bbox.ymin = br.ReadDouble(); 36 | bbox.xmax = br.ReadDouble(); 37 | bbox.ymax = br.ReadDouble(); 38 | numParts = br.ReadInt32(); 39 | numPoints = br.ReadInt32(); 40 | length += 44; 41 | parts = new int[numParts]; 42 | for (int i = 0; i < numParts; i++) 43 | parts[i] = br.ReadInt32(); 44 | length += 4 * numParts; 45 | points = new PointD[numPoints]; 46 | double x, y; 47 | for (int i = 0; i < numPoints; i++) 48 | { 49 | x = br.ReadDouble(); 50 | y = br.ReadDouble(); 51 | points[i] = new PointD(x, y); 52 | } 53 | length += 16 * numPoints; 54 | } 55 | 56 | /// 57 | /// 字节数 58 | /// 59 | public int Length 60 | { 61 | get { return this.length; } 62 | } 63 | 64 | public int NumPoints 65 | { 66 | get { return this.numPoints; } 67 | } 68 | 69 | public Point[] GetBMPPoints(BBOX boundarybox, int width, int height) 70 | { 71 | Point[] bmpPoints = new Point[numPoints]; 72 | for (int i = 0; i < numPoints; i++) 73 | { 74 | double x = width * (points[i].X - boundarybox.xmin) / (boundarybox.xmax - boundarybox.xmin); 75 | double y = height * (points[i].Y - boundarybox.ymin) / (boundarybox.ymax - boundarybox.ymin); 76 | bmpPoints[i] = new Point((int)x, height - (int)y); 77 | } 78 | return bmpPoints; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /WMSServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1B5E0584-8C6A-4232-97FD-D3E63D8B1783} 8 | Exe 9 | Properties 10 | WMSServer 11 | WMSServer 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | True 51 | True 52 | Resources.resx 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | ResXFileCodeGenerator 70 | Resources.Designer.cs 71 | 72 | 73 | 74 | 75 | Designer 76 | 77 | 78 | 79 | 86 | -------------------------------------------------------------------------------- /MapRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | using shp读取; 8 | 9 | namespace WMSServer 10 | { 11 | 12 | class MapRequest 13 | { 14 | private string service = "WMS"; 15 | private string request = "GetMap"; 16 | private string version = "1.3.0"; 17 | public string[] layers; 18 | public string[] styles; 19 | private string CRS = ""; 20 | public BBOX bbox; 21 | private string width = ""; 22 | private string height = ""; 23 | private string format = "png"; 24 | 25 | public MapRequest(string requestData) 26 | { 27 | try 28 | { 29 | Console.WriteLine(requestData); 30 | string temp = Regex.Match(requestData.Split('\n')[0], @"/.+?HTTP").Value; 31 | string paras = temp.Substring(1, temp.Length - 5); 32 | SetPara(paras); 33 | } 34 | catch (Exception ex) 35 | { 36 | throw ex; 37 | } 38 | } 39 | 40 | public int Width 41 | { 42 | get { return Int32.Parse(this.width); } 43 | } 44 | 45 | public int Height 46 | { 47 | get { return Int32.Parse(this.height); } 48 | } 49 | 50 | public string FORMAT 51 | { 52 | get { return format; } 53 | } 54 | 55 | private void SetPara(string paras) 56 | { 57 | try 58 | { 59 | string[] msgs = paras.Split(@"?&".ToArray(), StringSplitOptions.RemoveEmptyEntries); 60 | int n = msgs.Length; 61 | for (int i = 1; i < n; i++) 62 | SetParameter(msgs[i]); 63 | return; 64 | } 65 | catch (Exception ex) 66 | { 67 | throw ex; 68 | } 69 | } 70 | 71 | public void SetParameter(string msg) 72 | { 73 | try 74 | { 75 | string[] paras = msg.Split("= ".ToArray(), StringSplitOptions.RemoveEmptyEntries); 76 | if (string.Equals(paras[0], "version", StringComparison.OrdinalIgnoreCase)) 77 | version = paras[1]; 78 | else if (string.Equals(paras[0], "layers", StringComparison.OrdinalIgnoreCase)) 79 | { 80 | layers = paras[1].Split(','); //只能用逗号(“,”)作为列表中各个项之间的分隔符 81 | } 82 | else if (string.Equals(paras[0], "styles", StringComparison.OrdinalIgnoreCase)) 83 | { 84 | if (paras.Length == 2) 85 | styles = paras[1].Split(','); //只能用逗号(“,”)作为列表中各个项之间的分隔符 86 | else 87 | { 88 | styles = new string[1]; 89 | styles[0] = ""; 90 | } 91 | } 92 | else if (string.Equals(paras[0], "format", StringComparison.OrdinalIgnoreCase)) 93 | format = paras[1].Split('/')[1]; 94 | else if (string.Equals(paras[0], "BBOX", StringComparison.OrdinalIgnoreCase)) 95 | { 96 | string[] datas = paras[1].Split(','); //只能用逗号(“,”)作为列表中各个项之间的分隔符 97 | bbox = new BBOX(Double.Parse(datas[0]), Double.Parse(datas[1]), Double.Parse(datas[2]), Double.Parse(datas[3])); 98 | } 99 | else if (string.Equals(paras[0], "CRS", StringComparison.OrdinalIgnoreCase)) 100 | CRS = paras[1]; 101 | else if (string.Equals(paras[0], "Width", StringComparison.OrdinalIgnoreCase)) 102 | width = paras[1]; 103 | else if (string.Equals(paras[0], "Height", StringComparison.OrdinalIgnoreCase)) 104 | height = paras[1]; 105 | } 106 | catch (Exception) 107 | { 108 | throw new WMSExpection("操作请求包含无效参数值"); 109 | } 110 | return; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.34014 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WMSServer.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WMSServer.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 使用此强类型资源类,为所有资源查找 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找类似 This XML file does not appear to have any style information associated with it. The document tree is shown below. 65 | ///<WMS_Capabilities xmlns="http://www.opengis.net/wms" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.3.0" updateSequence="138" xsi:schemaLocation="http://www.opengis.net/wms http://localhost:8080/geoserver/schemas/wms/1.3.0/capabilities_1_3_0.xsd"> 66 | ///<Service> 67 | ///<Name>WMS</Name> 68 | ///<Title>GeoServer Web Map Service</Title> 69 | ///<Abstract> 70 | ///A co [字符串的其余部分被截断]"; 的本地化字符串。 71 | /// 72 | internal static string capability { 73 | get { 74 | return ResourceManager.GetString("capability", resourceCulture); 75 | } 76 | } 77 | 78 | /// 79 | /// 查找类似 <!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"><head><meta charset="utf-8" /><title>WMS ERROR</title></head><body>出错啦!HTTP异常代码:400 错<!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"><head><meta charset="utf-8" /><title>CWPWMS ERROR</title></head><body>出错啦!HTTP异常代码:400 错误信息: 的本地化字符串。 80 | /// 81 | internal static string errorPagePart1 { 82 | get { 83 | return ResourceManager.GetString("errorPagePart1", resourceCulture); 84 | } 85 | } 86 | 87 | /// 88 | /// 查找类似 </body></html> 的本地化字符串。 89 | /// 90 | internal static string errorPagePart2 { 91 | get { 92 | return ResourceManager.GetString("errorPagePart2", resourceCulture); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /WMSThreadHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Net.Sockets; 7 | 8 | namespace WMSServer 9 | { 10 | enum ServiceOperations 11 | { 12 | GetCapabilities, 13 | GetMap 14 | } 15 | 16 | class WMSThreadHandler 17 | { 18 | 19 | private TcpListener wmsListener; 20 | private string requestData; //请求字符串 21 | private string sMimeType; //请求格式 22 | private MapRequest mapReq; //GetMap请求 23 | private CapabilityRequest capalitityReq; 24 | private ServiceOperations serveType = ServiceOperations.GetCapabilities; 25 | public WMSThreadHandler(TcpListener mytcpListener) 26 | { 27 | this.wmsListener = mytcpListener; 28 | } 29 | 30 | public void HandleThread() 31 | { 32 | TcpClient client = wmsListener.AcceptTcpClient(); 33 | NetworkStream stream = client.GetStream(); 34 | try 35 | { 36 | GetRequest(ref stream); 37 | SendResponse(ref stream, GetResponceData()); 38 | } 39 | catch (Exception ex) 40 | { 41 | if (ex.GetType() == typeof(WMSExpection)) 42 | { 43 | Byte[] errordata = Encoding.UTF8.GetBytes(WMSServer.Properties.Resources.errorPagePart1 + ex.Message + WMSServer.Properties.Resources.errorPagePart2); 44 | sMimeType = ""; 45 | SendResponse(ref stream, errordata); 46 | } 47 | Console.WriteLine(ex.Message); 48 | return; 49 | } 50 | } 51 | 52 | private bool GetRequest(ref NetworkStream stream) 53 | { 54 | Byte[] data = new Byte[1024]; 55 | requestData = String.Empty; 56 | Int32 bytes = stream.Read(data, 0, data.Length); 57 | requestData = System.Text.Encoding.ASCII.GetString(data, 0, bytes); 58 | Console.WriteLine(requestData); 59 | try 60 | { 61 | if (requestData.IndexOf("Capabilities") != -1) //请求是GetCapabilities 62 | { 63 | capalitityReq = new CapabilityRequest(requestData); 64 | serveType = ServiceOperations.GetCapabilities; 65 | sMimeType = "text/xml"; 66 | } 67 | else //请求是GetMap 68 | { 69 | mapReq = new MapRequest(requestData); 70 | serveType = ServiceOperations.GetMap; 71 | sMimeType = mapReq.FORMAT; 72 | } 73 | } 74 | catch (Exception ex) 75 | { 76 | throw ex; 77 | } 78 | return true; 79 | } 80 | 81 | private Byte[] GetResponceData() 82 | { 83 | if (serveType == ServiceOperations.GetCapabilities) 84 | return WMS.GetCapabilityData(capalitityReq); 85 | else if (serveType == ServiceOperations.GetMap) 86 | return WMS.GetMap(mapReq); 87 | return null; 88 | } 89 | 90 | private void SendResponse(ref NetworkStream stream, Byte[] responseData) 91 | { 92 | int iTotBytes = responseData.Length; 93 | string sHttpVersion = requestData.Substring(requestData.IndexOf("HTTP", 1), 8); 94 | SendHeader(sHttpVersion, sMimeType, iTotBytes, " 200 OK", ref stream); 95 | SendToBrowser(responseData, ref stream); 96 | } 97 | 98 | private void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref NetworkStream mySocket) 99 | { 100 | String sBuffer = ""; 101 | if (sMIMEHeader.Length == 0) 102 | sMIMEHeader = "text/html"; 103 | sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n"; 104 | sBuffer = sBuffer + "Server: WMSServer\r\n"; 105 | sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n"; 106 | sBuffer = sBuffer + "Accept-Ranges: bytes\r\n"; 107 | sBuffer = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n"; 108 | Byte[] bSendData = Encoding.ASCII.GetBytes(sBuffer); 109 | Console.Write(sBuffer); 110 | SendToBrowser(bSendData, ref mySocket); 111 | } 112 | 113 | private void SendToBrowser(Byte[] bSendData, ref NetworkStream mySocket) 114 | { 115 | try 116 | { 117 | if (mySocket.CanWrite) 118 | mySocket.Write(bSendData, 0, bSendData.Length); 119 | Console.WriteLine("资源大小:" + bSendData.Length.ToString()); 120 | } 121 | catch (Exception e) 122 | { 123 | Console.WriteLine("发生错误 : {0} ", e); 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Shp读取与成图/Shapefile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | 8 | namespace shp读取 9 | { 10 | enum ShapeTypes 11 | { 12 | NullShape, Point, Polyline, Polygon, MultiPoint, PointZ, PolyLineZ, PolygonZ, MultiPointZ, PointM, PolyLineM, PolygonM, MultiPointM, MultiPatch 13 | } 14 | 15 | class Shapefile 16 | { 17 | int fileCode; 18 | int fileLength; //文件长度,单位:字节 19 | int version; //版本号 20 | int shapeTypeID; //集合类型 21 | ShapeTypes shapeType; 22 | double xmin, ymin, xmax, ymax, zmin, zmax, mmin, mmax; 23 | int byteCount = 0; //已经读取的字节数 24 | FeatureClass feature; 25 | 26 | public Shapefile(string filename) 27 | { 28 | FileStream fs = new FileStream(filename, FileMode.Open); 29 | BinaryReader br = new BinaryReader(fs); 30 | 31 | //读取文件头 32 | fileCode = ReverseByte(br.ReadInt32()); 33 | for (int i = 1; i <= 5; i++) 34 | br.ReadInt32(); 35 | fileLength = ReverseByte(br.ReadInt32()) * 2; 36 | version = br.ReadInt32(); 37 | shapeTypeID = br.ReadInt32(); 38 | xmin = br.ReadDouble(); 39 | ymin = br.ReadDouble(); 40 | xmax = br.ReadDouble(); 41 | ymax = br.ReadDouble(); 42 | zmin = br.ReadDouble(); 43 | zmax = br.ReadDouble(); 44 | mmin = br.ReadDouble(); 45 | mmax = br.ReadDouble(); 46 | byteCount += 100; 47 | 48 | switch (shapeTypeID) 49 | { 50 | case 1: 51 | { 52 | shapeType = ShapeTypes.Point; 53 | feature = ReadPointShp(br); 54 | break; 55 | } 56 | case 3: 57 | { 58 | shapeType = ShapeTypes.Polyline; 59 | feature = ReadPolyLineShp(br); 60 | break; 61 | } 62 | case 5: 63 | { 64 | shapeType = ShapeTypes.Polygon; 65 | feature = ReadPolygonShp(br); 66 | break; 67 | } 68 | default: 69 | { 70 | shapeType = ShapeTypes.NullShape; 71 | feature = new FeatureClass(); 72 | break; 73 | } 74 | } 75 | } 76 | 77 | /// 78 | /// 返回shapefile所对应的要素类 79 | /// 80 | /// 要素类 81 | public FeatureClass GetFeature() 82 | { 83 | return feature; 84 | } 85 | 86 | /// 87 | /// 大尾整数转小尾整数 88 | /// 89 | /// 大尾整数 90 | /// 小尾整数 91 | public static int ReverseByte(int big) 92 | { 93 | byte[] bytes = BitConverter.GetBytes(big); 94 | ExchangeByte(ref bytes[0], ref bytes[3]); 95 | ExchangeByte(ref bytes[1], ref bytes[2]); 96 | int little = BitConverter.ToInt32(bytes, 0); 97 | return little; 98 | } 99 | 100 | public static void ExchangeByte(ref byte b1, ref byte b2) 101 | { 102 | byte temp; 103 | temp = b1; 104 | b1 = b2; 105 | b2 = temp; 106 | } 107 | 108 | FeatureClass ReadPointShp(BinaryReader br) 109 | { 110 | List points = new List(); 111 | int recordNumber; //记录号 112 | int contentLength; //坐标记录长度 113 | int shapeType; //几何类型 114 | double x, y; 115 | while (byteCount < fileLength) 116 | { 117 | recordNumber = ReverseByte(br.ReadInt32()); 118 | contentLength = ReverseByte(br.ReadInt32()); 119 | shapeType = br.ReadInt32(); 120 | x = br.ReadDouble(); 121 | y = br.ReadDouble(); 122 | PointFeature p = new PointFeature(x, y); 123 | points.Add(p); 124 | byteCount += 28; 125 | } 126 | FeatureClass pointClass = new FeatureClass(points); 127 | return pointClass; 128 | } 129 | 130 | FeatureClass ReadPolyLineShp(BinaryReader br) 131 | { 132 | List polylines = new List(); 133 | while (byteCount < fileLength) 134 | { 135 | PolylineFeature temp = new PolylineFeature(br); 136 | byteCount += temp.Length; 137 | polylines.Add(temp); 138 | } 139 | FeatureClass polylineClass = new FeatureClass(polylines); 140 | return polylineClass; 141 | } 142 | 143 | FeatureClass ReadPolygonShp(BinaryReader br) 144 | { 145 | List polygons = new List(); 146 | while (byteCount < fileLength) 147 | { 148 | PolygonFeature temp = new PolygonFeature(br); 149 | byteCount += temp.ByteCount; 150 | polygons.Add(temp); 151 | } 152 | FeatureClass polygonClass = new FeatureClass(polygons); 153 | return polygonClass; 154 | } 155 | 156 | public double XMin 157 | { 158 | get { return this.xmin; } 159 | } 160 | public double YMin 161 | { 162 | get { return this.ymin; } 163 | } 164 | public double XMax 165 | { 166 | get { return this.xmax; } 167 | } 168 | public double YMax 169 | { 170 | get { return this.ymax; } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Shp读取与成图/FeatureClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Drawing; 7 | 8 | namespace shp读取 9 | { 10 | struct BBOX 11 | { 12 | public double xmin, ymin, xmax, ymax; 13 | 14 | public BBOX(double x1, double y1, double x2, double y2) 15 | { 16 | this.xmin = x1; 17 | this.ymin = y1; 18 | this.xmax = x2; 19 | this.ymax = y2; 20 | } 21 | } 22 | 23 | class FeatureClass 24 | { 25 | ShapeTypes shapetype; 26 | int count; 27 | public List points; 28 | public List polylines; 29 | public List polygons; 30 | 31 | public FeatureClass() 32 | { 33 | shapetype = ShapeTypes.NullShape; 34 | this.count = 0; 35 | } 36 | 37 | public FeatureClass(List pointsList) 38 | { 39 | shapetype = ShapeTypes.Point; 40 | this.points = pointsList; 41 | this.count = this.points.Count; 42 | } 43 | 44 | public FeatureClass(List polylinesList) 45 | { 46 | shapetype = ShapeTypes.Polyline; 47 | this.polylines = polylinesList; 48 | this.count = this.polylines.Count; 49 | } 50 | 51 | public FeatureClass(List polygonsList) 52 | { 53 | shapetype = ShapeTypes.Polygon; 54 | this.polygons = polygonsList; 55 | this.count = this.polygons.Count; 56 | } 57 | 58 | public ShapeTypes ShapeType 59 | { 60 | get { return this.shapetype; } 61 | } 62 | 63 | public int Count 64 | { 65 | get { return this.count; } 66 | } 67 | 68 | public Bitmap DrawBMP(BBOX boundarybox, Bitmap bmp) 69 | { 70 | int width = bmp.Width; 71 | int height = bmp.Height; 72 | Graphics graphic = Graphics.FromImage(bmp); 73 | Pen mypen = new Pen(Color.Black); 74 | 75 | Random ran = new Random(); 76 | int r = ran.Next(0, 255); 77 | int g = ran.Next(0, 255); 78 | int b = ran.Next(0, 255); 79 | Color brushcolor = Color.FromArgb(r, g, b); 80 | 81 | switch (shapetype) 82 | { 83 | case ShapeTypes.Point: 84 | for (int i = 0; i < points.Count; i++) 85 | { 86 | System.Drawing.Point bmpPoint = points[i].GetBMPPoint(boundarybox, width, height); 87 | Brush mybrush = new SolidBrush(Color.Green); 88 | Rectangle rect = new Rectangle(bmpPoint.X, bmpPoint.Y, 2, 2); 89 | graphic.DrawRectangle(mypen, rect); 90 | graphic.FillRectangle(mybrush, rect); 91 | } 92 | break; 93 | case ShapeTypes.Polyline: 94 | for (int i = 0; i < polylines.Count; i++) 95 | { 96 | System.Drawing.Point[] bmpPoints = polylines[i].GetBMPPoints(boundarybox, width, height); 97 | graphic.DrawLines(mypen, bmpPoints); 98 | } 99 | break; 100 | case ShapeTypes.Polygon: 101 | for (int i = 0; i < polygons.Count; i++) 102 | { 103 | System.Drawing.Point[] bmpPoints = polygons[i].GetBMPPoints(boundarybox, width, height); 104 | Brush mybrush = new SolidBrush(brushcolor); 105 | graphic.DrawPolygon(mypen, bmpPoints); 106 | graphic.FillPolygon(mybrush, bmpPoints); 107 | } 108 | break; 109 | default: 110 | break; 111 | } 112 | return bmp; 113 | } 114 | 115 | public Bitmap DrawBMP(BBOX boundarybox, Bitmap bmp, string style) 116 | { 117 | int width = bmp.Width; 118 | int height = bmp.Height; 119 | Graphics graphic = Graphics.FromImage(bmp); 120 | Pen mypen = new Pen(Color.Black); 121 | 122 | Color brushcolor = Color.Gray; 123 | switch (style) 124 | { 125 | case "Red": 126 | brushcolor = Color.Red; 127 | break; 128 | case "Green": 129 | brushcolor = Color.Green; 130 | break; 131 | case "Blue": 132 | brushcolor = Color.Blue; 133 | break; 134 | case "Cyan": 135 | brushcolor = Color.Cyan; 136 | break; 137 | case "Magenta": 138 | brushcolor = Color.Magenta; 139 | break; 140 | case "Yellow": 141 | brushcolor = Color.Yellow; 142 | break; 143 | default: 144 | break; 145 | } 146 | 147 | switch (shapetype) 148 | { 149 | case ShapeTypes.Point: 150 | for (int i = 0; i < points.Count; i++) 151 | { 152 | Point bmpPoint = points[i].GetBMPPoint(boundarybox, width, height); 153 | Brush mybrush = new SolidBrush(Color.Green); 154 | Rectangle rect = new Rectangle(bmpPoint.X, bmpPoint.Y, 2, 2); 155 | graphic.DrawRectangle(mypen, rect); 156 | graphic.FillRectangle(mybrush, rect); 157 | } 158 | break; 159 | case ShapeTypes.Polyline: 160 | for (int i = 0; i < polylines.Count; i++) 161 | { 162 | Point[] bmpPoints = polylines[i].GetBMPPoints(boundarybox, width, height); 163 | graphic.DrawLines(mypen, bmpPoints); 164 | } 165 | break; 166 | case ShapeTypes.Polygon: 167 | for (int i = 0; i < polygons.Count; i++) 168 | { 169 | Point[] bmpPoints = polygons[i].GetBMPPoints(boundarybox, width, height); 170 | Brush mybrush = new SolidBrush(brushcolor); 171 | graphic.DrawPolygon(mypen, bmpPoints); 172 | graphic.FillPolygon(mybrush, bmpPoints); 173 | } 174 | break; 175 | default: 176 | break; 177 | } 178 | return bmp; 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\capability.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312 123 | 124 | 125 | <!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"><head><meta charset="utf-8" /><title>WMS ERROR</title></head><body>出错啦!HTTP异常代码:400 错<!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"><head><meta charset="utf-8" /><title>CWPWMS ERROR</title></head><body>出错啦!HTTP异常代码:400 错误信息: 126 | 127 | 128 | </body></html> 129 | 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WMS-Server 2 | A server which implements OGC Web Map Service (WMS) (http://www.opengeospatial.org/standards/wms) by C# 3 | 4 | 5 | ## 一、什么是WMS 6 | WMS(Web Map Service,Web地图服务)是OGC(Open GIS Consortium,开放地理信息系统协会)制定的一种能够从地理信息动态生成具有地理空间位置数据的地图图像的服务标准。WMS标准将由地理信息图示表达的“地图”定义为计算机屏幕上显示的数字图像文件,因此WMS产生的地图一般以图像格式提供,如PNG、GIF 或BMP;或按SVG(Scalable Vector Graphics)或WebCGM(Web Computer Graphics Metafile)格式提供基于矢量的图形元素。 7 | WMS标准定义了三个基本操作:第一个操作是GetCapabilities,用于返回服务级元数据,它是对服务信息内容和要求参数的一种描述;第二个操作是GetMap,用于返回一个地图图像,其地理空间参考和大小参数是明确定义的;可选的第三个操作是GetFeatureInfo,返回显示在地图上的某些具体要素的信息。本文只实现WMS的两个必选操作。 8 | 用户可以通过使用标准的网络浏览器或地图客户端(如Gaia)以统一资源定位符(Uniform Resources Locators,URL)的形式发出请求来调用网络地图服务的操作。URL的内容取决于被请求的操作的要求。特别是当请求一幅地图时,URL需要指出地图所要显示的地理信息(图层)、地图的覆盖范围、指定的空间参照系以及输出图像的宽度和高度;当利用同样的地理信息参数和输出范围(Boundary Box,BBOX)产生两幅或多幅地图时,其结果可以准确地被叠加以产生复合地图。 9 | 10 | ## 二、WMS的capability.xml 11 | 在实现WMS时,首先要需要根据OGC制定的WMS实现规范写一个capability的xml文档,里面提供了WMS的服务级元数据,包括服务信息内容和要求参数等。在用户向服务器发送GetCapabilities请求时,服务器返回此xml文档,用户通过阅读这个xml文档可以了解到WMS提供了哪些数据、具体实现了规范中的哪些功能等。而诸如Gaia等地图客户端会通过分析capability.xml自动得到提供的图层和实现的格式、样式等(图1)。 12 | 13 |
14 | 15 |
16 | 17 |

图1 Gaia客户端对于capability的分析

18 | 19 | capability.xml有两个一级标签,分别是。其中标签记录了此WMS服务的名字、关键词等基本信息,同时给出了服务提供人的联系信息,包括所在地、单位、E-mail等,方便用户在需要时与服务提供人联系。 20 | 标签是capability.xml的核心内容。标签下有三个主要子标签标签记录了WMS所支持的请求的内容,包括返回的格式和请求URL前缀。标签说明了异常的格式。标签先记录了WMS整体上支持的坐标系和边界范围(BoundingBox),再详细记录了每个空间数据图层的关键词、坐标系、边界范围、可以选择的样式 87 | 88 | 89 | 90 | Street 91 | Street 92 | 93 | 94 | features 95 | Street 96 | 97 | EPSG:4326 98 | 99 | 100 | 105 | 106 | 107 | 108 | Water 109 | Water 110 | 111 | 112 | Water 113 | features 114 | 115 | EPSG:4326 116 | 117 | 118 | 122 | 126 | 130 | 134 | 138 | 142 | 143 | 144 | 145 | garden_path 146 | garden_path 147 | 148 | 149 | features 150 | garden_path 151 | 152 | EPSG:4326 153 | 154 | 155 | 160 | 161 | 162 | 163 | path 164 | path 165 | 166 | 167 | features 168 | path 169 | 170 | EPSG:4326 171 | 172 | 173 | 178 | 179 | 180 | 181 | playground 182 | playground 183 | 184 | 185 | features 186 | playground 187 | 188 | EPSG:4326 189 | 190 | 191 | 195 | 199 | 203 | 207 | 211 | 215 | 216 | 217 | 218 | restaurant 219 | restaurant 220 | 221 | 222 | features 223 | restaurant 224 | 225 | EPSG:4326 226 | 227 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | 253 | 254 | 255 | businessbuilding 256 | businessbuilding 257 | 258 | 259 | features 260 | businessbuilding 261 | 262 | EPSG:4326 263 | 264 | 265 | 269 | 273 | 277 | 281 | 285 | 289 | 290 | 291 | 292 | officebuilding 293 | officebuilding 294 | 295 | 296 | features 297 | officebuilding 298 | 299 | EPSG:4326 300 | 301 | 302 | 306 | 310 | 314 | 318 | 322 | 326 | 327 | 328 | 329 | towel 330 | towel 331 | 332 | 333 | features 334 | towel 335 | 336 | EPSG:4326 337 | 338 | 339 | 344 | 345 | 346 | 347 | dormitory 348 | dormitory 349 | 350 | 351 | features 352 | dormitory 353 | 354 | EPSG:4326 355 | 356 | 357 | 361 | 365 | 369 | 373 | 377 | 381 | 382 | 383 | 384 | constructionsite 385 | constructionsite 386 | 387 | 388 | features 389 | constructionsite 390 | 391 | EPSG:4326 392 | 393 | 394 | 398 | 402 | 406 | 410 | 414 | 418 | 419 | 420 | 421 | teachingbuilding 422 | teachingbuilding 423 | 424 | 425 | features 426 | teachingbuilding 427 | 428 | EPSG:4326 429 | 430 | 431 | 435 | 439 | 443 | 447 | 451 | 455 | 456 | 457 | 458 | scenepoint 459 | scenepoint 460 | 461 | 462 | features 463 | scenepoint 464 | 465 | EPSG:4326 466 | 467 | 468 | 469 | 470 | 471 | servicebuilding 472 | servicebuilding 473 | 474 | 475 | features 476 | servicebuilding 477 | 478 | EPSG:4326 479 | 480 | 481 | 485 | 489 | 493 | 497 | 501 | 505 | 506 | 507 | 508 | importantbuilding 509 | importantbuilding 510 | 511 | 512 | features 513 | importantbuilding 514 | 515 | EPSG:4326 516 | 517 | 518 | 522 | 526 | 530 | 534 | 538 | 542 | 543 | 544 | 545 | gate 546 | gate 547 | 548 | 549 | features 550 | gate 551 | 552 | EPSG:4326 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | --------------------------------------------------------------------------------