在构建数据源下载文件的叙述性说明第一步
如此XML结构体
<?xml version="1.0" encoding="utf-8"?> <onlinemapsources> <onlineMapSource> <name>GaoDeDiTuImage</name> <url><![CDATA[http://webst0{$s}.is.autonavi.com/appmaptile?style=6&x={$x}&y={$y}&z={$z}]]></url> <servers>1,2,3,4</servers> </onlineMapSource> </onlinemapsources>
当中NAME节点描写叙述下载地图数据源名称
url为须要下载数据源切片的訪问方式的URL
servers为在线地图的服务器个数。
以下我们以天地图为例
首先构建DATASROUS对象 全部数据源的基类
/// <summary> /// 全部数据缓存下载转换的基类 /// </summary> public abstract class DataSourceBase { ~DataSourceBase() { if (_connLocalCacheFile != null) _connLocalCacheFile.Close(); _connLocalCacheFile = null; } /// <summary> /// 提前定义或者在线地图 /// </summary> public string Type { get; set; } /// <summary> /// 数据服务地址 /// </summary> public string Path { get; set; } /// <summary> /// 服务的元数据信息 /// </summary> public TilingScheme TilingScheme { get; set; } /// <summary> /// 表述该地图源头为在线地图 /// 非常多方法数据的下载取决于这个属性 /// </summary> public bool IsOnlineMap { get; set; }
/// <summary> /// 初始化 对象生成下载和转换方案 /// </summary> protected virtual void Initialize(string path) { this.Path = path; TilingScheme ts; try { ReadTilingScheme(out ts); } catch (Exception e) { throw new Exception("读取瓦片的元数据失败!\r\n" + e.Message+"\r\n"+e.StackTrace); } TilingScheme = ts; IsOnlineMap = IsOnlineMaps(Type); }
/// <summary> /// TODO: 读取相应数据源的元数据信息 /// </summary> /// <param name="tilingScheme"></param> /// <param name="lodsJson"></param> protected abstract void ReadTilingScheme(out TilingScheme tilingScheme);
/// <summary> /// 生成JSON字符串 /// </summary> /// <param name="tilingScheme"></param> /// <returns></returns> protected TilingScheme TilingSchemePostProcess(TilingScheme tilingScheme) { #region ArcGIS REST Service Info string pjson = @"{ ""currentVersion"" : 10.01, ""serviceDescription"" : ""This service is populated from PortableBasemapServer by diligentpig. For more information goto http://newnaw.com"", ""mapName"" : ""Layers"", ""description"" : ""none"", ""copyrightText"" : ""IMapGeoServer by diligentpig, REST API by Esri"", ""layers"" : [ { ""id"" : 0, ""name"" : ""YourServiceNameHere"", ""parentLayerId"" : -1, ""defaultVisibility"" : true, ""subLayerIds"" : null, ""minScale"" : 0, ""maxScale"" : 0 } ], ""tables"" : [ ], ""spatialReference"" : { ""wkid"" : " + tilingScheme.WKID + @" }, ""singleFusedMapCache"" : true, ""tileInfo"" : { ""rows"" : " + tilingScheme.TileRows + @", ""cols"" : " + tilingScheme.TileCols + @", ""dpi"" : " + tilingScheme.DPI + @", ""format"" : """ + tilingScheme.CacheTileFormat + @""", ""compressionQuality"" : " + tilingScheme.CompressionQuality + @", ""origin"" : { ""x"" : " + tilingScheme.TileOrigin.X + @", ""y"" : " + tilingScheme.TileOrigin.Y + @" }, ""spatialReference"" : { ""wkid"" : " + tilingScheme.WKID + @" }, ""lods"" : [" + tilingScheme.LODsJson + @" ] }, ""initialExtent"" : { ""xmin"" : " + tilingScheme.InitialExtent.XMin + @", ""ymin"" : " + tilingScheme.InitialExtent.YMin + @", ""xmax"" : " + tilingScheme.InitialExtent.XMax + @", ""ymax"" : " + tilingScheme.InitialExtent.YMax + @", ""spatialReference"" : { ""wkid"" : " + tilingScheme.WKID + @" } }, ""fullExtent"" : { ""xmin"" : " + tilingScheme.FullExtent.XMin + @", ""ymin"" : " + tilingScheme.FullExtent.YMin + @", ""xmax"" : " + tilingScheme.FullExtent.XMax + @", ""ymax"" : " + tilingScheme.FullExtent.YMax + @", ""spatialReference"" : { ""wkid"" : " + tilingScheme.WKID + @" } }, ""units"" : ""esriMeters"", ""supportedImageFormatTypes"" : ""PNG24,PNG,JPG,DIB,TIFF,EMF,PS,PDF,GIF,SVG,SVGZ,AI,BMP"", ""documentInfo"" : { ""Title"" : ""none"", ""Author"" : ""none"", ""Comments"" : ""none"", ""Subject"" : ""none"", ""Category"" : ""none"", ""Keywords"" : ""none"", ""Credits"" : ""diligentpig"" }, ""capabilities"" : ""Map,Query,Data"" } "; #endregion tilingScheme.RestResponseArcGISPJson = pjson; tilingScheme.RestResponseArcGISJson = pjson.Replace("\r\n", "").Replace("\n", ""); return tilingScheme; }
/// <summary> /// TODO: 获取瓦片的的二进制文件 /// </summary> /// <param name="level"></param> /// <param name="row"></param> /// <param name="col"></param> /// <returns></returns> public abstract byte[] GetTileBytes(int level, int row, int col); /// <summary> /// 当瓦片開始载入的时候运行 /// </summary> public EventHandler<TileLoadEventArgs> TileLoaded;
#region 读取瓦片的的元数据 protected void ReadSqliteTilingScheme(out TilingScheme tilingScheme, SQLiteConnection sqlConn) { tilingScheme = new TilingScheme(); StringBuilder sb; #region 读取MBtile中的元数据信息 tilingScheme.Path = "N/A"; bool isMACFile = false; using (SQLiteCommand cmd = new SQLiteCommand(sqlConn)) { cmd.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='info'"; long i = (long)cmd.ExecuteScalar(); if (i == 0) isMACFile = false; else isMACFile = true; if (!isMACFile) { cmd.CommandText = string.Format("SELECT value FROM metadata WHERE name='format'"); object o = cmd.ExecuteScalar(); if (o != null) { string f = o.ToString(); tilingScheme.CacheTileFormat = f.ToUpper().Contains("PNG") ?
ImageFormat.PNG : ImageFormat.JPG; } else { tilingScheme.CacheTileFormat = ImageFormat.JPG; } } } tilingScheme.CompressionQuality = 75; tilingScheme.DPI = 96; tilingScheme.LODs = new LODInfo[20]; const double cornerCoordinate = 20037508.342787; double resolution = cornerCoordinate * 2 / 256; double scale = 591657527.591555; for (int i = 0; i < tilingScheme.LODs.Length; i++) { tilingScheme.LODs[i] = new LODInfo() { Resolution = resolution, LevelID = i, Scale = scale }; resolution /= 2; scale /= 2; } sb = new StringBuilder("\r\n"); foreach (LODInfo lod in tilingScheme.LODs) { sb.Append(@" {""level"":" + lod.LevelID + "," + @"""resolution"":" + lod.Resolution + "," + @"""scale"":" + lod.Scale + @"}," + "\r\n"); } tilingScheme.LODsJson = sb.ToString().Remove(sb.ToString().Length - 3); try { using (SQLiteCommand sqlCmd = new SQLiteCommand(sqlConn)) { sqlCmd.CommandText = string.Format("SELECT value FROM metadata WHERE name='bounds'"); object o = sqlCmd.ExecuteScalar(); if (o != null) { string[] bounds = o.ToString().Split(new char[] { ',' }); Point leftBottom = new Point(double.Parse(bounds[0]), double.Parse(bounds[1])); Point rightTop = new Point(double.Parse(bounds[2]), double.Parse(bounds[3])); leftBottom = Utility.GeographicToWebMercator(leftBottom); rightTop = Utility.GeographicToWebMercator(rightTop); tilingScheme.InitialExtent = new Envelope(leftBottom.X, leftBottom.Y, rightTop.X, rightTop.Y); tilingScheme.FullExtent = tilingScheme.InitialExtent; } else { throw new Exception(); } } } catch (Exception) { tilingScheme.InitialExtent = new Envelope(-cornerCoordinate, -cornerCoordinate, cornerCoordinate, cornerCoordinate); tilingScheme.FullExtent = tilingScheme.InitialExtent; } tilingScheme.PacketSize = 0; tilingScheme.StorageFormat = StorageFormat.esriMapCacheStorageModeExploded; tilingScheme.TileCols = tilingScheme.TileRows = 256; tilingScheme.TileOrigin = new Point(-cornerCoordinate, cornerCoordinate); tilingScheme.WKID = 3857; tilingScheme.WKT = @"PROJCS[""WGS_1984_Web_Mercator_Auxiliary_Sphere"",GEOGCS[""GCS_WGS_1984"",DATUM[""D_WGS_1984"",SPHEROID[""WGS_1984"",6378137.0,298.257223563]],PRIMEM[""Greenwich"",0.0],UNIT[""Degree"",0.0174532925199433]],PROJECTION[""Mercator_Auxiliary_Sphere""],PARAMETER[""False_Easting"",0.0],PARAMETER[""False_Northing"",0.0],PARAMETER[""Central_Meridian"",0.0],PARAMETER[""Standard_Parallel_1"",0.0],PARAMETER[""Auxiliary_Sphere_Type"",0.0],UNIT[""Meter"",1.0],AUTHORITY[""ESRI"",""3857""]]"; #endregion }
/// <summary> /// /// </summary> /// <param name="path">切片方案的路径而不是数据源头的路径</param> /// <param name="tilingScheme"></param> protected void ReadArcGISTilingSchemeFile(string path, out TilingScheme tilingScheme) { tilingScheme = new TilingScheme(); StringBuilder sb; #region 读取arcgis缓存的描写叙述文件 if (!System.IO.File.Exists(path))//当数据产生缓存时候path是一个文件夹 { path += "\\conf.xml"; } tilingScheme.Path = path;//构建完整的文件夹地址 //读取配置描写叙述文件 XElement confXml = XElement.Load(System.IO.Path.GetDirectoryName(path) + @"\\conf.xml"); tilingScheme.WKT = confXml.Element("TileCacheInfo").Element("SpatialReference").Element("WKT").Value; if (confXml.Element("TileCacheInfo").Element("SpatialReference").Element("WKID") != null) tilingScheme.WKID = int.Parse(confXml.Element("TileCacheInfo").Element("SpatialReference").Element("WKID").Value); else tilingScheme.WKID = -1; tilingScheme.TileOrigin = new Point( double.Parse(confXml.Element("TileCacheInfo").Element("TileOrigin").Element("X").Value), double.Parse(confXml.Element("TileCacheInfo").Element("TileOrigin").Element("Y").Value)); tilingScheme.DPI = int.Parse(confXml.Element("TileCacheInfo").Element("DPI").Value); int lodsCount = confXml.Element("TileCacheInfo").Element("LODInfos").Elements().Count(); tilingScheme.LODs = new LODInfo[lodsCount]; for (int i = 0; i < lodsCount; i++) { tilingScheme.LODs[i] = new LODInfo() { LevelID = i, Scale = double.Parse(confXml.Element("TileCacheInfo").Element("LODInfos").Elements().ElementAt(i).Element("Scale").Value), Resolution = double.Parse(confXml.Element("TileCacheInfo").Element("LODInfos").Elements().ElementAt(i).Element("Resolution").Value) }; } sb = new StringBuilder("\r\n"); foreach (LODInfo lod in tilingScheme.LODs) { sb.Append(@" {""level"":" + lod.LevelID + "," + @"""resolution"":" + lod.Resolution + "," + @"""scale"":" + lod.Scale + @"}," + "\r\n"); } tilingScheme.LODsJson = sb.ToString().Remove(sb.ToString().Length - 3);//remove last "," and "\r\n" tilingScheme.TileCols = int.Parse(confXml.Element("TileCacheInfo").Element("TileCols").Value); tilingScheme.TileRows = int.Parse(confXml.Element("TileCacheInfo").Element("TileRows").Value); tilingScheme.CacheTileFormat = (ImageFormat)Enum.Parse(typeof(ImageFormat), confXml.Element("TileImageInfo").Element("CacheTileFormat").Value.ToUpper()); tilingScheme.CompressionQuality = int.Parse(confXml.Element("TileImageInfo").Element("CompressionQuality").Value); tilingScheme.StorageFormat = (StorageFormat)Enum.Parse(typeof(StorageFormat), confXml.Element("CacheStorageInfo").Element("StorageFormat").Value); tilingScheme.PacketSize = int.Parse(confXml.Element("CacheStorageInfo").Element("PacketSize").Value); //read conf.cdi XElement confCdi = XElement.Load(System.IO.Path.GetDirectoryName(path) + @"\\conf.cdi"); try { tilingScheme.FullExtent = new Envelope( double.Parse(confCdi.Element("XMin").Value), double.Parse(confCdi.Element("YMin").Value), double.Parse(confCdi.Element("XMax").Value), double.Parse(confCdi.Element("YMax").Value)); } catch (Exception e) { throw new Exception("the content of conf.cdi file is not valid!" + e.Message); } tilingScheme.InitialExtent = tilingScheme.FullExtent; #endregion }
/// <summary> /// 创建TilingScheme解析ArcGISTiledMapService信息 /// </summary> /// <param name="ht">哈希表包括全部ArcGISTiledMapService信息解析JSON util类.</param> /// <param name="tilingScheme"></param> protected void ReadArcGISTiledMapServiceTilingScheme(Hashtable ht, out TilingScheme tilingScheme) { tilingScheme = new TilingScheme(); StringBuilder sb; #region 读取缓存的元数据 tilingScheme.Path = "N/A"; tilingScheme.WKT = (ht["spatialReference"] as Hashtable)["wkt"] == null ?
"Absent" : (string)(ht["spatialReference"] as Hashtable)["wkt"]; tilingScheme.WKID = int.Parse((ht["spatialReference"] as Hashtable)["wkid"].ToString()); tilingScheme.TileOrigin = new Point( (double)((ht["tileInfo"] as Hashtable)["origin"] as Hashtable)["x"], (double)((ht["tileInfo"] as Hashtable)["origin"] as Hashtable)["y"]); tilingScheme.DPI = int.Parse((ht["tileInfo"] as Hashtable)["dpi"].ToString()); //LODInfos int lodsCount = ((ht["tileInfo"] as Hashtable)["lods"] as ArrayList).Count; tilingScheme.LODs = new LODInfo[lodsCount]; for (int i = 0; i < lodsCount; i++) { tilingScheme.LODs[i] = new LODInfo() { LevelID = i, Scale = (double)(((ht["tileInfo"] as Hashtable)["lods"] as ArrayList)[i] as Hashtable)["scale"], Resolution = (double)(((ht["tileInfo"] as Hashtable)["lods"] as ArrayList)[i] as Hashtable)["resolution"] }; } sb = new StringBuilder("\r\n"); foreach (LODInfo lod in tilingScheme.LODs) { sb.Append(@" {""level"":" + lod.LevelID + "," + @"""resolution"":" + lod.Resolution + "," + @"""scale"":" + lod.Scale + @"}," + "\r\n"); } tilingScheme.LODsJson = sb.ToString().Remove(sb.ToString().Length - 3);//remove last "," and "\r\n" tilingScheme.TileCols = int.Parse((ht["tileInfo"] as Hashtable)["cols"].ToString()); tilingScheme.TileRows = int.Parse((ht["tileInfo"] as Hashtable)["rows"].ToString()); tilingScheme.CacheTileFormat = (ImageFormat)Enum.Parse(typeof(ImageFormat), (ht["tileInfo"] as Hashtable)["format"].ToString().ToUpper()); tilingScheme.CompressionQuality = int.Parse((ht["tileInfo"] as Hashtable)["compressionQuality"].ToString()); tilingScheme.StorageFormat = StorageFormat.unknown;//ArcGISTiledMapService doesn't expose this property tilingScheme.PacketSize = int.MinValue;
tilingScheme.FullExtent = new Envelope( (double)(ht["fullExtent"] as Hashtable)["xmin"], (double)(ht["fullExtent"] as Hashtable)["ymin"], (double)(ht["fullExtent"] as Hashtable)["xmax"], (double)(ht["fullExtent"] as Hashtable)["ymax"]); tilingScheme.InitialExtent = new Envelope( (double)(ht["initialExtent"] as Hashtable)["xmin"], (double)(ht["initialExtent"] as Hashtable)["ymin"], (double)(ht["initialExtent"] as Hashtable)["xmax"], (double)(ht["initialExtent"] as Hashtable)["ymax"]); #endregion }
protected void ReadArcGISTilePackageTilingSchemeFile(string path, out TilingScheme tilingScheme) { tilingScheme = new TilingScheme(); StringBuilder sb; #region 读取缓存的元数据 tilingScheme.Path = "v101/Layers/conf.xml"; using (Stream streamConfxml = new MemoryStream(Utility.GetEntryBytesFromZIPFile(path, "v101/Layers/conf.xml"))) { if (streamConfxml == null) { throw new Exception("conf.xml not found in " + "v101/Layers/conf.xml of " + System.IO.Path.GetFileName(path)); } //read conf.xml XElement confXml = XElement.Load(streamConfxml); tilingScheme.WKT = confXml.Element("TileCacheInfo").Element("SpatialReference").Element("WKT").Value; if (confXml.Element("TileCacheInfo").Element("SpatialReference").Element("WKID") != null) tilingScheme.WKID = int.Parse(confXml.Element("TileCacheInfo").Element("SpatialReference").Element("WKID").Value); else tilingScheme.WKID = -1; tilingScheme.TileOrigin = new Point( double.Parse(confXml.Element("TileCacheInfo").Element("TileOrigin").Element("X").Value), double.Parse(confXml.Element("TileCacheInfo").Element("TileOrigin").Element("Y").Value)); tilingScheme.DPI = int.Parse(confXml.Element("TileCacheInfo").Element("DPI").Value); //LODInfos int lodsCount = confXml.Element("TileCacheInfo").Element("LODInfos").Elements().Count(); tilingScheme.LODs = new LODInfo[lodsCount]; for (int i = 0; i < lodsCount; i++) { tilingScheme.LODs[i] = new LODInfo() { LevelID = i, Scale = double.Parse(confXml.Element("TileCacheInfo").Element("LODInfos").Elements().ElementAt(i).Element("Scale").Value), Resolution = double.Parse(confXml.Element("TileCacheInfo").Element("LODInfos").Elements().ElementAt(i).Element("Resolution").Value) }; } sb = new StringBuilder("\r\n"); //{"level" : 0, "resolution" : 156543.033928, "scale" : 591657527.591555}, foreach (LODInfo lod in tilingScheme.LODs) { sb.Append(@" {""level"":" + lod.LevelID + "," + @"""resolution"":" + lod.Resolution + "," + @"""scale"":" + lod.Scale + @"}," + "\r\n"); } tilingScheme.LODsJson = sb.ToString().Remove(sb.ToString().Length - 3);//remove last "," and "\r\n" tilingScheme.TileCols = int.Parse(confXml.Element("TileCacheInfo").Element("TileCols").Value); tilingScheme.TileRows = int.Parse(confXml.Element("TileCacheInfo").Element("TileRows").Value); tilingScheme.CacheTileFormat = (ImageFormat)Enum.Parse(typeof(ImageFormat), confXml.Element("TileImageInfo").Element("CacheTileFormat").Value.ToUpper()); tilingScheme.CompressionQuality = int.Parse(confXml.Element("TileImageInfo").Element("CompressionQuality").Value); tilingScheme.StorageFormat = (StorageFormat)Enum.Parse(typeof(StorageFormat), confXml.Element("CacheStorageInfo").Element("StorageFormat").Value); tilingScheme.PacketSize = int.Parse(confXml.Element("CacheStorageInfo").Element("PacketSize").Value); } using (Stream streamConfcdi = new MemoryStream(Utility.GetEntryBytesFromZIPFile(path, "v101/Layers/conf.cdi"))) { if (streamConfcdi == null) { throw new Exception("conf.cdi not found in " + path); } //read conf.cdi XElement confCdi = XElement.Load(streamConfcdi); try { tilingScheme.FullExtent = new Envelope( double.Parse(confCdi.Element("XMin").Value), double.Parse(confCdi.Element("YMin").Value), double.Parse(confCdi.Element("XMax").Value), double.Parse(confCdi.Element("YMax").Value)); } catch (Exception e) { throw new Exception("the content of conf.cdi file is not valid!" + e.Message); } tilingScheme.InitialExtent = tilingScheme.FullExtent; } #endregion }
protected void ReadGoogleMapsTilingScheme(out TilingScheme tilingScheme) { tilingScheme = new TilingScheme(); StringBuilder sb; #region 谷歌必应地图的元数据 tilingScheme.Path = "N/A"; tilingScheme.CacheTileFormat = ImageFormat.JPG; tilingScheme.CompressionQuality = 75; tilingScheme.DPI = 96; tilingScheme.LODs = new LODInfo[20]; const double cornerCoordinate = 20037508.342787; double resolution = cornerCoordinate * 2 / 256; double scale = 591657527.591555; for (int i = 0; i < tilingScheme.LODs.Length; i++) { tilingScheme.LODs[i] = new LODInfo() { Resolution = resolution, LevelID = i, Scale = scale }; resolution /= 2; scale /= 2; } //create json sb = new StringBuilder("\r\n"); //{"level" : 0, "resolution" : 156543.033928, "scale" : 591657527.591555}, foreach (LODInfo lod in tilingScheme.LODs) { sb.Append(@" {""level"":" + lod.LevelID + "," + @"""resolution"":" + lod.Resolution + "," + @"""scale"":" + lod.Scale + @"}," + "\r\n"); } tilingScheme.LODsJson = sb.ToString().Remove(sb.ToString().Length - 3);//remove last "," and "\r\n" //two extent tilingScheme.InitialExtent = new Envelope(-cornerCoordinate, -cornerCoordinate, cornerCoordinate, cornerCoordinate); tilingScheme.FullExtent = tilingScheme.InitialExtent; tilingScheme.PacketSize = 0; tilingScheme.StorageFormat = StorageFormat.esriMapCacheStorageModeExploded; tilingScheme.TileCols = tilingScheme.TileRows = 256; tilingScheme.TileOrigin = new Point(-cornerCoordinate, cornerCoordinate); tilingScheme.WKID = 3857;//102100; tilingScheme.WKT = @"PROJCS[""WGS_1984_Web_Mercator_Auxiliary_Sphere"",GEOGCS[""GCS_WGS_1984"",DATUM[""D_WGS_1984"",SPHEROID[""WGS_1984"",6378137.0,298.257223563]],PRIMEM[""Greenwich"",0.0],UNIT[""Degree"",0.0174532925199433]],PROJECTION[""Mercator_Auxiliary_Sphere""],PARAMETER[""False_Easting"",0.0],PARAMETER[""False_Northing"",0.0],PARAMETER[""Central_Meridian"",0.0],PARAMETER[""Standard_Parallel_1"",0.0],PARAMETER[""Auxiliary_Sphere_Type"",0.0],UNIT[""Meter"",1.0],AUTHORITY[""ESRI"",""3857""]]"; #endregion }
protected void ReadTianDiTuTilingScheme(out TilingScheme tilingScheme) { tilingScheme = new TilingScheme(); StringBuilder sb; #region 天地图的元数据 tilingScheme.Path = "N/A"; tilingScheme.CacheTileFormat = ImageFormat.JPEG; tilingScheme.CompressionQuality = 75; tilingScheme.DPI = 96; //LODs tilingScheme.LODs = new LODInfo[17]; double resolution = 90 / 256d; double scale = 147914677.73;//147748799.285417; for (int i = 0; i < tilingScheme.LODs.Length; i++) { tilingScheme.LODs[i] = new LODInfo() { Resolution = resolution, LevelID = i, Scale = scale }; resolution /= 2; scale /= 2; } //create json sb = new StringBuilder("\r\n"); //{"level" : 0, "resolution" : 156543.033928, "scale" : 591657527.591555}, foreach (LODInfo lod in tilingScheme.LODs) { sb.Append(@" {""level"":" + lod.LevelID + "," + @"""resolution"":" + lod.Resolution + "," + @"""scale"":" + lod.Scale + @"}," + "\r\n"); } tilingScheme.LODsJson = sb.ToString().Remove(sb.ToString().Length - 3);//remove last "," and "\r\n" //two extent tilingScheme.InitialExtent = new Envelope(-180, -90, 180, 90); tilingScheme.FullExtent = tilingScheme.InitialExtent; tilingScheme.PacketSize = 0; tilingScheme.StorageFormat = StorageFormat.esriMapCacheStorageModeExploded; tilingScheme.TileCols = tilingScheme.TileRows = 256; tilingScheme.TileOrigin = new Point(-180, 90); tilingScheme.WKID = 4326; tilingScheme.WKT = @"GEOGCS[""WGS 84"",DATUM[""WGS_1984"",SPHEROID[""WGS 84"",6378137,298.257223563,AUTHORITY[""EPSG"",""7030""]],AUTHORITY[""EPSG"",""6326""]],PRIMEM[""Greenwich"",0,AUTHORITY[""EPSG"",""8901""]],UNIT[""degree"",0.01745329251994328,AUTHORITY[""EPSG"",""9122""]],AUTHORITY[""EPSG"",""4326""]]"; #endregion } #endregion
public static bool IsOnlineMaps(string type) { bool isPredefinedDataSource = false; foreach (var str in Enum.GetValues(typeof(DataSourceTypePredefined))) { if (string.Equals(type, str.ToString())) { isPredefinedDataSource = true; break; } } return !isPredefinedDataSource; }
protected byte[] HttpGetTileBytes(string uri) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.Accept = "*/*"; request.KeepAlive = true; request.Method = "GET"; if (this.Type == DataSourceTypePredefined.ArcGISTiledMapService.ToString()) { request.Referer = this.Path + "?f=jsapi"; } request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4"; request.Proxy = null;//==no proxy request.Timeout = 20000; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { if (!response.ContentType.ToLower().Contains("image")) throw new Exception("download(http get) result is not image"); return Util.Utility.StreamToBytes(response.GetResponseStream()); } }
protected byte[] HttpPostTileBytes(string url, string queryData) { HttpWebRequest request; request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.Accept = "text/html, image/png, image/jpeg, image/gif, */*;q=0.1"; request.KeepAlive = true; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4"; request.Proxy = null;//GlobalProxySelection.GetEmptyWebProxy(); byte[] data = Encoding.UTF8.GetBytes(queryData); request.ContentLength = data.Length; using (Stream stream = request.GetRequestStream()) { stream.Write(data, 0, data.Length); } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { if (!response.ContentType.ToLower().Contains("image")) throw new Exception("download(http post) result is not image"); return Util.Utility.StreamToBytes(response.GetResponseStream()); } }
#region Local File Cache /// <summary> /// by checking keyword to determin if sqlite file is IMapGeoServer created local cache file. /// </summary> private string constIMapGeoServerFileCacheKeyword = "___IMapGeoServerLOCALCACHE___"; private string _localCacheFileName;
public string LocalCacheFileName { get { return _localCacheFileName; } set { _localCacheFileName = value; } } private SQLiteConnection _connLocalCacheFile; private ConcurrentDictionary<string, byte[]> _dictTilesToBeLocalCached = new ConcurrentDictionary<string, byte[]>(); /// <summary> /// 检查本地缓存文件相应onlinemap是有效的。
假设无效或不存在,创建新的。 /// </summary> /// <param name="localCacheFileName">本地缓存文件的名称(.cache)</param> protected void ValidateLocalCacheFile(string localCacheFileName) { _localCacheFileName = localCacheFileName; try { if (File.Exists(localCacheFileName)) { #region 推断文件是否有效 using (SQLiteConnection conn = new SQLiteConnection("Data source = " + localCacheFileName)) { conn.Open(); using (SQLiteCommand cmd = new SQLiteCommand(conn)) { cmd.CommandText = "SELECT value FROM metadata WHERE name='name'"; object o = cmd.ExecuteScalar(); if (o != null && o.ToString().Equals(constIMapGeoServerFileCacheKeyword)) { _connLocalCacheFile = new SQLiteConnection("Data Source=" + _localCacheFileName); _connLocalCacheFile.Open(); return; } else { try { File.Delete(localCacheFileName); } catch (Exception e) { throw new Exception("Init online maps local cache file failed.\r\n" + e.Message); } } } } #endregion } #region 创建sqllite数据库 SQLiteConnection.CreateFile(localCacheFileName); using (SQLiteConnection conn = new SQLiteConnection("Data source = " + localCacheFileName)) { conn.Open(); using (SQLiteTransaction transaction = conn.BeginTransaction()) { using (SQLiteCommand cmd = new SQLiteCommand(conn)) { #region 创建table和索引 //ref http://mapbox.com/developers/mbtiles/ //metadata table cmd.CommandText = "CREATE TABLE metadata (name TEXT, value TEXT)"; cmd.ExecuteNonQuery(); //images table cmd.CommandText = "CREATE TABLE images (tile_data BLOB, tile_id TEXT)"; cmd.ExecuteNonQuery(); //map table cmd.CommandText = "CREATE TABLE map (zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_id TEXT)"; cmd.ExecuteNonQuery(); //tiles view cmd.CommandText = @"CREATE VIEW tiles AS SELECT map.zoom_level AS zoom_level, map.tile_column AS tile_column, map.tile_row AS tile_row, images.tile_data AS tile_data FROM map JOIN images ON images.tile_id = map.tile_id"; cmd.ExecuteNonQuery(); //indexes cmd.CommandText = "CREATE UNIQUE INDEX images_id on images (tile_id)"; cmd.ExecuteNonQuery(); cmd.CommandText = "CREATE UNIQUE INDEX map_index on map (zoom_level, tile_column, tile_row)"; cmd.ExecuteNonQuery(); cmd.CommandText = @"CREATE UNIQUE INDEX name ON metadata (name)"; cmd.ExecuteNonQuery(); #endregion #region 写入元数据信息 //name cmd.CommandText = @"INSERT INTO metadata(name,value) VALUES (""name"",""" + constIMapGeoServerFileCacheKeyword + @""")"; cmd.ExecuteNonQuery(); //type cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('type','baselayer')"; cmd.ExecuteNonQuery(); //version cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('version','1.2')"; cmd.ExecuteNonQuery(); //no description //format string f = TilingScheme.CacheTileFormat.ToString().ToUpper().Contains("PNG") ?
"png" : "jpg"; cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('format','" + f + "')"; cmd.ExecuteNonQuery(); //no bounds //no attribution #endregion } transaction.Commit(); } } #endregion _connLocalCacheFile = new SQLiteConnection("Data Source=" + _localCacheFileName); _connLocalCacheFile.Open(); } catch (Exception e) { throw new Exception("Validating local cache file error!\r\n" + e.Message); } }
/// <summary> /// 从本地尝试检索瓷砖byte[]。缓存文件。返回byte[]假设成功,null假设失败了。
/// </summary> /// <param name="level"></param> /// <param name="row"></param> /// <param name="col"></param> /// <returns></returns> public byte[] GetTileBytesFromLocalCache(int level, int row, int col) { if (!IsOnlineMap && !(this is DataSourceRasterImage)) return null; int tmsCol, tmsRow; Utility.ConvertGoogleTileToTMSTile(level, row, col, out tmsRow, out tmsCol); string commandText = string.Format("SELECT {0} FROM tiles WHERE tile_column={1} AND tile_row={2} AND zoom_level={3}", "tile_data", tmsCol, tmsRow, level); if (_connLocalCacheFile.State.ToString() == "Closed") { _connLocalCacheFile.Open(); } using (SQLiteCommand sqlCmd = new SQLiteCommand(commandText, _connLocalCacheFile)) { object o = sqlCmd.ExecuteScalar(); if (o != null) { return (byte[])o; } return null; } } /// <summary> /// 发生在瓦载入和瓷砖保存到本地文件缓存 /// </summary> /// <param name="o"></param> /// <param name="a">TileLoadEventArgs</param> protected void InternalOnTileLoaded(object o, TileLoadEventArgs a) { if (a.GeneratedMethod != TileGeneratedSource.DynamicOutput) return; if (o is DataSourceRasterImage && !ConfigManager.App_AllowFileCacheOfRasterImage || IsOnlineMap && !ConfigManager.App_AllowFileCacheOfOnlineMaps) return;
int tmsRow, tmsCol; Utility.ConvertGoogleTileToTMSTile(a.Level, a.Row, a.Column, out tmsRow, out tmsCol); string key = string.Format("{0}/{1}/{2}", a.Level, tmsCol, tmsRow); if (_dictTilesToBeLocalCached.ContainsKey(key)) return; _dictTilesToBeLocalCached.TryAdd(key, a.TileBytes); if (_dictTilesToBeLocalCached.Count ==1000) { WriteTilesToLocalCacheFile(_dictTilesToBeLocalCached); _dictTilesToBeLocalCached.Clear(); } } /// <summary> /// 当下载在线地图或者栅格图片把瓦片数据下乳缓存文件 /// </summary> /// <param name="dict"></param> protected void WriteTilesToLocalCacheFile(ConcurrentDictionary<string, byte[]> dict) { lock (_locker) { try { using (SQLiteConnection conn = new SQLiteConnection("Data source = " + _localCacheFileName)) { conn.Open(); using (SQLiteTransaction transaction = conn.BeginTransaction()) { using (SQLiteCommand cmd = new SQLiteCommand(conn)) { foreach (KeyValuePair<string, byte[]> kvp in dict) { //key = "level/col/row" int level = int.Parse(kvp.Key.Split(new char[] { '/' })[0]); int col = int.Parse(kvp.Key.Split(new char[] { '/' })[1]); int row = int.Parse(kvp.Key.Split(new char[] { '/' })[2]); string guid = Guid.NewGuid().ToString(); cmd.CommandText = "INSERT INTO images VALUES (@tile_data,@tile_id)"; cmd.Parameters.AddWithValue("tile_data", kvp.Value); cmd.Parameters.AddWithValue("tile_id", guid); cmd.ExecuteNonQuery(); cmd.CommandText = "INSERT INTO map VALUES (@zoom_level,@tile_column,@tile_row,@tile_id)"; cmd.Parameters.AddWithValue("zoom_level", level); cmd.Parameters.AddWithValue("tile_column", col); cmd.Parameters.AddWithValue("tile_row", row); cmd.Parameters.AddWithValue("tile_id", guid); cmd.ExecuteNonQuery(); } } transaction.Commit(); } } } catch (Exception e) { throw new Exception("Writing tiles to local .cache file error!\r\n" + e.Message); } } } #endregion
#region 转换状态 private ConvertStatus _convertingStatus; /// <summary> /// 缓存转换状态 /// </summary> public ConvertStatus ConvertingStatus { get { return _convertingStatus; } protected set { _convertingStatus = value; } } #region ToMBTiles private string _outputFile; private static readonly object _locker = new object(); private long _completeCount, _levelCompleteCount, _totalCount, _levelTotalCount, _errorCount, _levelErrorCount, _completeTotalBytes; /// <summary> /// constrain the tile downloading to the extent of an envelope or boundary shape of a polygon. /// </summary> private Geometry _downloadGeometry; private CancellationTokenSource _cts = new CancellationTokenSource(); /// <summary> /// Do convert jobs from various datasource to MBTiles. Datasource must be in 3857 tilingscheme. /// </summary> /// <param name="outputPath">full output file name and path.</param> /// <param name="name">optional by mbtiles.</param> /// <param name="description">optional by mbtiles.</param> /// <param name="attribution">optional by mbtiles.</param> /// <param name="levels">tiles in which levels to convert to mbtiles.</param> /// <param name="geometry">convert/download extent, sr=3857. If this is Envelope, download by rectangle, if this is polygon, download by polygon's shape.</param> /// <param name="doCompact">implementing the reducing redundant tile bytes part of MBTiles specification?</param> protected void DoConvertToMBTiles(string outputPath, string name, string description, string attribution, int[] levels, Geometry geometry, bool doCompact) { _outputFile = outputPath; _downloadGeometry = geometry; _convertingStatus.IsInProgress = true; try { CreateMBTilesFileAndWriteMetaData(outputPath, name, description, attribution, geometry); #region calculate startCol/Row and endCol/Row and tiles count of each level int constTileSize = 256; _convertingStatus.TotalCount = 0; string[] keyTileInfos = new string[levels.Length]; int[] tilesCountOfLevel = new int[levels.Length]; for (int i = 0; i < levels.Length; i++) { LODInfo lod = TilingScheme.LODs[levels[i]]; double oneTileDistance = lod.Resolution * constTileSize; int startTileRow = (int)(Math.Abs(TilingScheme.TileOrigin.Y - geometry.Extent.YMax) / oneTileDistance); int startTileCol = (int)(Math.Abs(TilingScheme.TileOrigin.X - geometry.Extent.XMin) / oneTileDistance); int endTileRow = (int)(Math.Abs(TilingScheme.TileOrigin.Y - geometry.Extent.YMin) / oneTileDistance); int endTileCol = (int)(Math.Abs(TilingScheme.TileOrigin.X - geometry.Extent.XMax) / oneTileDistance); keyTileInfos[i] = string.Format("{0},{1},{2},{3}", startTileRow, startTileCol, endTileRow, endTileCol); tilesCountOfLevel[i] = Math.Abs((endTileCol - startTileCol + 1) * (endTileRow - startTileRow + 1)); _convertingStatus.TotalCount += tilesCountOfLevel[i]; } _totalCount = _convertingStatus.TotalCount; _completeCount = _errorCount = 0; #endregion for (int i = 0; i < levels.Length; i++) { int level, startR, startC, endR, endC;//startTileRow,startTileCol,... level = TilingScheme.LODs[levels[i]].LevelID; startR = int.Parse(keyTileInfos[i].Split(new char[] { ',' })[0]); startC = int.Parse(keyTileInfos[i].Split(new char[] { ',' })[1]); endR = int.Parse(keyTileInfos[i].Split(new char[] { ',' })[2]); endC = int.Parse(keyTileInfos[i].Split(new char[] { ',' })[3]); _convertingStatus.Level = level; _convertingStatus.LevelTotalCount = tilesCountOfLevel[i]; _convertingStatus.LevelCompleteCount = _convertingStatus.LevelErrorCount = 0; _levelTotalCount = _convertingStatus.LevelTotalCount; _levelCompleteCount = _levelErrorCount = 0; SaveOneLevelTilesToMBTiles(level, startR, startC, endR, endC); if (_convertingStatus.IsCancelled) { _convertingStatus.IsCompletedSuccessfully = false; break; } } if (doCompact) { _convertingStatus.IsDoingCompact = true; _convertingStatus.SizeBeforeCompact = new FileInfo(_outputFile).Length; CompactMBTiles(_outputFile); _convertingStatus.IsDoingCompact = false; _convertingStatus.SizeAfterCompact = new FileInfo(_outputFile).Length; } if (!_convertingStatus.IsCancelled) _convertingStatus.IsCompletedSuccessfully = true; } finally { _convertingStatus.IsInProgress = false; _convertingStatus.IsCommittingTransaction = false; _convertingStatus.IsDoingCompact = false; } }
/// <summary> /// process all tiles in a level and save them in sqlite db, with multi threads /// </summary> /// <param name="level">level number</param> /// <param name="startRowLevel">start row number of full extent of this level</param> /// <param name="startColLevel"></param> /// <param name="endRowLevel"></param> /// <param name="endColLevel"></param> private void SaveOneLevelTilesToMBTiles(int level, int startRowLevel, int startColLevel, int endRowLevel, int endColLevel) { int bundleSize = IsOnlineMap ? 16 : 128; Bundle startBundle = new Bundle(bundleSize, level, startRowLevel / bundleSize, startColLevel / bundleSize, TilingScheme); Bundle endBundle = new Bundle(bundleSize, level, endRowLevel / bundleSize, endColLevel / bundleSize, TilingScheme); List<Bundle> allBundles = new List<Bundle>(); for (int bRow = startBundle.Row; bRow <= endBundle.Row; bRow++) { for (int bCol = startBundle.Col; bCol <= endBundle.Col; bCol++) { Bundle b = new Bundle(bundleSize, level, bRow, bCol, TilingScheme); if (_downloadGeometry is Polygon) { bool bPolygonTouchesWithBundle = false; Polygon polygon = _downloadGeometry as Polygon; if (polygon.ContainsPoint(b.Extent.LowerLeft) || polygon.ContainsPoint(b.Extent.LowerRight) || polygon.ContainsPoint(b.Extent.UpperLeft) || polygon.ContainsPoint(b.Extent.UpperRight)) bPolygonTouchesWithBundle = true; if (b.Extent.ContainsPoint(polygon.Extent.LowerLeft) && b.Extent.ContainsPoint(polygon.Extent.LowerRight) && b.Extent.ContainsPoint(polygon.Extent.UpperLeft) && b.Extent.ContainsPoint(polygon.Extent.UpperRight)) bPolygonTouchesWithBundle = true; if (polygon.IsIntersectsWithPolygon(b.Extent.ToPolygon())) bPolygonTouchesWithBundle = true; if (!bPolygonTouchesWithBundle) continue; } allBundles.Add(b); } } int maxThreadCount = IsOnlineMap ? 50 : 5; int queueCount = allBundles.Count % maxThreadCount == 0 ?
allBundles.Count / maxThreadCount : allBundles.Count / maxThreadCount + 1; for (int queue = 0; queue < queueCount; queue++) { int startBundleIndex = maxThreadCount * queue; int endBundleIndex = startBundleIndex + maxThreadCount - 1; endBundleIndex = endBundleIndex > allBundles.Count ? allBundles.Count - 1 : endBundleIndex; List<Task> tasks = new List<Task>(); for (int i = startBundleIndex; i <= endBundleIndex; i++) { if (_convertingStatus.IsCancelled) return; Bundle b = allBundles[i]; int startR = startRowLevel > b.StartTileRow ? startRowLevel : b.StartTileRow; int startC = startColLevel > b.StartTileCol ? startColLevel : b.StartTileCol; int endR = endRowLevel > b.EndTileRow ?
b.EndTileRow : endRowLevel; int endC = endColLevel > b.EndTileCol ? b.EndTileCol : endColLevel; Task t = Task.Factory.StartNew(() => { WriteTilesToSqlite(GetTilesByExtent(level, startR, startC, endR, endC)); }, _cts.Token); tasks.Add(t); } _convertingStatus.ThreadCount = tasks.Count; try { Task.WaitAll(tasks.ToArray()); } catch (AggregateException) { } } }
/// <summary> /// Notify all converting tasks to cancel. The db transaction has began will still need sometime to be completed. /// </summary> protected void CancelDoConvertToMBTiles() { _convertingStatus.IsCancelled = true; _cts.Cancel(); }
/// <summary> /// Get tiles of specified extent. /// </summary> /// <param name="level"></param> /// <param name="startRow"></param> /// <param name="startCol"></param> /// <param name="endRow"></param> /// <param name="endCol"></param> /// <returns>A Dictionary which stores the tiles bytes. key patten is "level/col/row".</returns> private Dictionary<string, byte[]> GetTilesByExtent(int level, int startRow, int startCol, int endRow, int endCol) { Dictionary<string, byte[]> dict = new Dictionary<string, byte[]>(); for (int r = startRow; r <= endRow; r++) { for (int c = startCol; c <= endCol; c++) { byte[] bytes = GetTileBytes(level, r, c); if (bytes != null) { dict.Add(string.Format("{0}/{1}/{2}", level, c, r), bytes); try { _convertingStatus.LevelCompleteCount = Interlocked.Increment(ref _levelCompleteCount); _convertingStatus.CompleteCount = Interlocked.Increment(ref _completeCount); _convertingStatus.CompleteTotalBytes = Interlocked.Add(ref _completeTotalBytes, bytes.Length); } catch (Exception ex) { throw; } } else { _convertingStatus.LevelErrorCount = Interlocked.Increment(ref _levelErrorCount); _convertingStatus.ErrorCount = Interlocked.Increment(ref _errorCount); } #if Debug System.Diagnostics.Debug.WriteLine(_convertingStatus.LevelCompleteCount + " / " + _convertingStatus.LevelTotalCount + " ||| " + level + "/" + r + "/" + c + "thread:" + Thread.CurrentThread.ManagedThreadId); #endif } } return dict; }
/// <summary> /// Write tiles in Dictionary to Sqlite file. /// </summary> /// <param name="dict">the Dictionary which contains tiles bytes to write. key patten is "level/col/row".</param> private void WriteTilesToSqlite(Dictionary<string, byte[]> dict) { lock (_locker) { using (SQLiteConnection conn = new SQLiteConnection("Data source = " + _outputFile)) { conn.Open(); SQLiteTransaction transaction = conn.BeginTransaction(); try { using (SQLiteCommand cmd = new SQLiteCommand(conn)) { foreach (KeyValuePair<string, byte[]> kvp in dict) { int level = int.Parse(kvp.Key.Split(new char[] { '/' })[0]); int col = int.Parse(kvp.Key.Split(new char[] { '/' })[1]); int row = int.Parse(kvp.Key.Split(new char[] { '/' })[2]); int tmsRow, tmsCol; Utility.ConvertGoogleTileToTMSTile(level, row, col, out tmsRow, out tmsCol); string guid = Guid.NewGuid().ToString(); cmd.CommandText = "INSERT INTO images VALUES (@tile_data,@tile_id)"; cmd.Parameters.AddWithValue("tile_data", kvp.Value); cmd.Parameters.AddWithValue("tile_id", guid); cmd.ExecuteNonQuery(); cmd.CommandText = "INSERT INTO map VALUES (@zoom_level,@tile_column,@tile_row,@tile_id)"; cmd.Parameters.AddWithValue("zoom_level", level); cmd.Parameters.AddWithValue("tile_column", tmsCol); cmd.Parameters.AddWithValue("tile_row", tmsRow); cmd.Parameters.AddWithValue("tile_id", guid); cmd.ExecuteNonQuery(); } } _convertingStatus.IsCommittingTransaction = true; transaction.Commit(); _convertingStatus.IsCommittingTransaction = false; } catch (Exception e) { } finally { if (transaction != null) transaction.Dispose(); } } } }
/// <summary> /// implementing the reducing redundant tile bytes part of MBTiles specification. /// </summary> /// <param name="fileName">MBTiles file name.</param> private void CompactMBTiles(string fileName) { try { using (SQLiteConnection conn = new SQLiteConnection("Data source = " + fileName)) { conn.Open(); List<int> duplicateLength = new List<int>(); using (SQLiteCommand cmd = new SQLiteCommand(conn)) { cmd.CommandText = "SELECT tile_data,count(*) as counts FROM images GROUP BY tile_data HAVING count(*) > 1"; SQLiteDataReader dr = cmd.ExecuteReader(); while (dr.Read()) { if (!duplicateLength.Contains(((byte[])dr[0]).Length)) duplicateLength.Add(((byte[])dr[0]).Length); } dr.Close(); foreach (int length in duplicateLength) { cmd.CommandText = "SELECT tiles.zoom_level as zoom_level,tiles.tile_column as tile_column,tiles.tile_row as tile_row,tiles.tile_data as tile_data,map.tile_id as tile_id FROM tiles JOIN map ON map.zoom_level=tiles.zoom_level AND map.tile_column=tiles.tile_column AND map.tile_row=tiles.tile_row WHERE length(tile_data)=" + length; SQLiteDataReader row = cmd.ExecuteReader(); Dictionary<string, byte[]> uniqueBytes = new Dictionary<string, byte[]>(); using (SQLiteTransaction transaction = conn.BeginTransaction()) { using (SQLiteCommand cmd1 = new SQLiteCommand(conn)) { while (row.Read()) { bool isRedundant = false; if (uniqueBytes.Count == 0) { uniqueBytes.Add(row["tile_id"].ToString(), (byte[])row["tile_data"]); continue; } foreach (KeyValuePair<string, byte[]> kvp in uniqueBytes) { if (IsByteArrayEquivalent((byte[])row["tile_data"], kvp.Value)) { isRedundant = true;
cmd1.CommandText = string.Format("UPDATE map SET tile_id = '{0}' WHERE zoom_level = {1} AND tile_column = {2} AND tile_row = {3} ", kvp.Key, int.Parse(row["zoom_level"].ToString()), int.Parse(row["tile_column"].ToString()), int.Parse(row["tile_row"].ToString())); cmd1.ExecuteNonQuery(); cmd1.CommandText = "DELETE FROM images WHERE tile_id='" + row["tile_id"].ToString() + "'"; cmd1.ExecuteNonQuery();
break; } } if (!isRedundant) uniqueBytes.Add(row["tile_id"].ToString(), (byte[])row["tile_data"]); } } row.Close(); transaction.Commit(); } } cmd.CommandText = "VACUUM"; cmd.ExecuteNonQuery(); } } } catch (Exception e) { throw new Exception("compacting MBTiles error!\r\n" + e.Message); } }
private bool IsByteArrayEquivalent(byte[] bytes1, byte[] bytes2) { if (bytes1.Length != bytes2.Length) return false; for (int i = 0; i < bytes1.Length; i++) { if (bytes1[i] != bytes2[i]) return false; } return true; }
/// <summary> /// create the .mbtiles file and initialize tables, views and write metadata. /// </summary> /// <param name="outputPath"></param> /// <param name="name"></param> /// <param name="description"></param> /// <param name="attribution"></param> private void CreateMBTilesFileAndWriteMetaData(string outputPath, string name, string description, string attribution, Geometry geometry) { //check the wkid if (!TilingScheme.WKID.Equals(102100) && !TilingScheme.WKID.Equals(3857)) { throw new Exception("The WKID of ArcGIS Cache is not 3857 or 102100!"); } //check the numbers of lods if (TilingScheme.LODs.Length != 20) { throw new Exception("The count of levels must be 20! Current levels count = " + TilingScheme.LODs.Length); } //check tiling scheme origin if (Math.Abs(TilingScheme.TileOrigin.X + 20037508.342787) > 0.1) { throw new Exception("The tiling scheme origin is not correct!"); } //check the tile dimension if (!TilingScheme.TileCols.Equals(256) || !TilingScheme.TileRows.Equals(256)) { throw new Exception("The size of a tile is not 256*256!"); } //create new sqlite database try { SQLiteConnection.CreateFile(outputPath); } catch (Exception ex) { throw; } using (SQLiteConnection conn = new SQLiteConnection("Data source = " + outputPath)) { this._connLocalCacheFile = conn; conn.Open(); using (SQLiteTransaction transaction = conn.BeginTransaction()) { using (SQLiteCommand cmd = new SQLiteCommand(conn)) { #region create tables and indexes //ref http://mapbox.com/developers/mbtiles/ //metadata table cmd.CommandText = "CREATE TABLE metadata (name TEXT, value TEXT)"; cmd.ExecuteNonQuery(); //images table cmd.CommandText = "CREATE TABLE images (tile_data BLOB, tile_id TEXT)"; cmd.ExecuteNonQuery(); //map table cmd.CommandText = "CREATE TABLE map (zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_id TEXT)"; cmd.ExecuteNonQuery(); //tiles view cmd.CommandText = @"CREATE VIEW tiles AS SELECT map.zoom_level AS zoom_level, map.tile_column AS tile_column, map.tile_row AS tile_row, images.tile_data AS tile_data FROM map JOIN images ON images.tile_id = map.tile_id"; cmd.ExecuteNonQuery(); //indexes cmd.CommandText = "CREATE UNIQUE INDEX images_id on images (tile_id)"; cmd.ExecuteNonQuery(); cmd.CommandText = "CREATE UNIQUE INDEX map_index on map (zoom_level, tile_column, tile_row)"; cmd.ExecuteNonQuery(); cmd.CommandText = @"CREATE UNIQUE INDEX name ON metadata (name)"; cmd.ExecuteNonQuery(); #endregion #region write metadata //name cmd.CommandText = @"INSERT INTO metadata(name,value) VALUES (""name"",""" + name + @""")"; cmd.ExecuteNonQuery(); //type cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('type','baselayer')"; cmd.ExecuteNonQuery(); //version cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('version','1.2')"; cmd.ExecuteNonQuery(); //description cmd.CommandText = @"INSERT INTO metadata(name,value) VALUES (""description"",""" + description + @""")"; cmd.ExecuteNonQuery(); //format string f = TilingScheme.CacheTileFormat.ToString().ToUpper().Contains("PNG") ?
"png" : "jpg"; cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('format','" + f + "')"; cmd.ExecuteNonQuery(); //bounds Point bottomLeft = Utility.WebMercatorToGeographic(new Point(geometry.Extent.XMin, geometry.Extent.YMin)); Point upperRight = Utility.WebMercatorToGeographic(new Point(geometry.Extent.XMax, geometry.Extent.YMax)); cmd.CommandText = "INSERT INTO metadata(name,value) VALUES ('bounds','" + string.Format("{0},{1},{2},{3}", bottomLeft.X.ToString(), bottomLeft.Y.ToString(), upperRight.X.ToString(), upperRight.Y.ToString()) + "')"; cmd.ExecuteNonQuery(); //attribution cmd.CommandText = @"INSERT INTO metadata(name,value) VALUES (""attribution"",""" + attribution + @""")"; cmd.ExecuteNonQuery(); #endregion } transaction.Commit(); } } } #endregion #endregion }
/// <summary> ///地图数据源类型 /// </summary> public enum DataSourceTypePredefined { MobileAtlasCreator, MBTiles, ArcGISCache, ArcGISTilePackage, ArcGISDynamicMapService, ArcGISTiledMapService, ArcGISImageService, RasterImage, OGCWMSService, AutoNaviCache, TianDiTuAnnotation, TianDiTuMap, }
public class TilingScheme { /// <summary> /// tiling scheme file path /// </summary> public string Path { get; set; } public string RestResponseArcGISJson { get; set; } public string RestResponseArcGISPJson { get; set; } public int WKID { get; set; } public string WKT { get; set; } public int TileCols { get; set; } public int TileRows { get; set; } /// <summary> /// PNG/PNG32/PNG24/PNG8/JPEG/JPG/Mixed /// </summary> public ImageFormat CacheTileFormat { get; set; } /// <summary> /// png=0,jpg=XX /// </summary> public int CompressionQuality { get; set; } public Point TileOrigin { get; set; } public LODInfo[] LODs { get; set; } public string LODsJson { get; set; } public Envelope InitialExtent { get; set; } public Envelope FullExtent { get; set; } public StorageFormat StorageFormat { get; set; } public int PacketSize { get; set; } public int DPI { get; set; } }
public class LODInfo { public int LevelID { get; set; } public double Scale { get; set; } public double Resolution { get; set; } } /// <summary> /// 存储格式 /// </summary> public enum StorageFormat { esriMapCacheStorageModeExploded, esriMapCacheStorageModeCompact, unknown//ArcGISTiledMapService doesn't expose this property } /// <summary> /// 图片类型 /// </summary> public enum ImageFormat { PNG, PNG32, PNG24, PNG8, JPG, JPEG, MIXED }
public class TileLoadEventArgs : EventArgs { public int Level { get; set; } public int Column { get; set; } public int Row { get; set; } public byte[] TileBytes { get; set; } public TileGeneratedSource GeneratedMethod { get; set; } }
public enum TileGeneratedSource { DynamicOutput, FromMemcached, FromFileCache }
然后构建天地图数据实体对象取名为DataSourceTianDiTuMap.cs
DataSourceBase { public DataSourceTianDiTuMap() { Initialize("N/A"); }
protected override void Initialize(string path) { this.Type = DataSourceTypePredefined.TianDiTuMap.ToString(); base.Initialize(path); }
protected override void ReadTilingScheme(out TilingScheme tilingScheme) { ReadTianDiTuTilingScheme(out tilingScheme); this.TilingScheme = TilingSchemePostProcess(tilingScheme); }
public override byte[] GetTileBytes(int level, int row, int col) { string baseUrl = string.Empty; string[] subDomains = null; string subdomain = string.Empty; string uri = string.Empty; string baseUrl0 = "http://tile{0}.tianditu.com/DataServer?T=A0512_EMap&X={1}&Y={2}&L={3}"; string baseUrl1 = "http://tile{0}.tianditu.com/DataServer?
T=B0627_EMap1112&X={1}&Y={2}&L={3}"; string baseUrl2 = "http://tile{0}.tianditu.com/DataServer?
T=siwei0608&X={1}&Y={2}&L={3}"; subDomains = new string[] { "0", "1", "2", "3", "4", "5", "6", "7" }; subdomain = subDomains[(level + col + row) % subDomains.Length]; if (level + 2 < 11) uri = string.Format(baseUrl0, subdomain, col, row, level + 2); else if (level + 2 < 13) uri = string.Format(baseUrl1, subdomain, col, row, level + 2); else if (level + 2 < 19) uri = string.Format(baseUrl2, subdomain, col, row, level + 2); try { return HttpGetTileBytes(uri); } catch (Exception e) { //if server has response(not a downloading error) and tell IMapGeoServer do not have the specific tile, return null if (e is WebException && (e as WebException).Response != null && ((e as WebException).Response as HttpWebResponse).StatusCode == HttpStatusCode.NotFound) return null;
string suffix = this.TilingScheme.CacheTileFormat.ToString().ToUpper().Contains("PNG") ? "png" : "jpg"; Stream stream = this.GetType().Assembly.GetManifestResourceStream("IMapGeoServer.Assets.badrequest" + this.TilingScheme.TileCols + "." + suffix); byte[] bytes = new byte[stream.Length]; stream.Read(bytes, 0, bytes.Length); return bytes; } }
以上代码请细致阅读代码片段会陆续更新
版权声明:本文博客原创文章,博客,未经同意,不得转载。
转载于:https://www.cnblogs.com/bhlsheji/p/4632740.html
相关资源:数据结构—成绩单生成器