第二章 自己的框架WMTS服务,下载数据集成的文章1

在构建数据源下载文件的叙述性说明第一步

如此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 = "

T=B0627_EMap1112&X={1}&Y={2}&L={3">http://tile{0}.tianditu.com/DataServer?

T=B0627_EMap1112&X={1}&Y={2}&L={3}";

string baseUrl2 = "

T=siwei0608&X={1}&Y={2}&L={3">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;

}

}

以上代码请细致阅读代码片段会陆续更新



版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-10-29 00:23:17

第二章 自己的框架WMTS服务,下载数据集成的文章1的相关文章

第二章:创建框架和窗体

没有翻译第一章是由于第一章仅仅介绍了怎样设置IDE.这方面网上文章非常多,我就没有翻译,直接从第二章開始. 以下是原文链接.翻译有不正确的地方请朋友们指正. http://www.rastertek.com/gl40tut02.html Tutorial 2: Creating a Framework and Window This OpenGL 4.0 tutorial will cover setting up a basic frame work and window. 这一章涵盖了创建基

第二章:创建框架和窗口

没有翻译第一章是因为第一章只介绍了如何设置IDE,这方面网上文章很多,我就没有翻译,直接从第二章开始. 下面是原文链接,翻译有不对的地方请朋友们指正. http://www.rastertek.com/gl40tut02.html Tutorial 2: Creating a Framework and Window This OpenGL 4.0 tutorial will cover setting up a basic frame work and window. 这一章涵盖了创建基本框架

第二章 变量和数据类型

课时6:数据和数据类型 1.数据及数据类型 数据:指有用的信息 数据类型:对数据的分类 2.C#语言中的数据类型 Char字符类型 单个文字 (汉字,字母,数字,标点符号) 成对英文单引号表示 'A' string字符串类型 不限数量文字 (汉字,字母,数字,标点符号) 成对英文单引号示 "A" int整数类型 (简称整型) 表示一个整数 直接书写 100 double小数类型 表示包含小数点的数字 直接书写 1.1 课时7:认识变量 1.认识变量:一块存储数据的内存空间,并且该内存区

第一章 项目背景【制作属于自己的wmts服务多源空间数据服务整合开发--减少项目成本让客户更放心】

     最近项目中遇到了基于skyline 加载离线地图的这样的工作.针对这个问题找了好多的解决方案都没有能够解决.最后因缘巧合的想到了一个构建本地wmts服务[skyline6.5以上的版本支持].通过网上大量的浏览搜索资料.找了一些开源的项目.终于把问题给解决了. 1.数据的离线下载 开发的工具支持谷歌.必应.天地图.高德等等互联网上的数据的下载然后数据重组整合多源的数据整合发布为wmts. 支持 对arcgis发布的wms rest  title.image等格式的服务代理转换为wm

openwrt教程 第二章 下载openwrt源码

2.1 开发环境 我们工作室(F403科技创意室:http://f403tech.taobao.com/)写的该教程,所使用的环境为: VMware Workstation:VMware 8 Ubuntu:Ubuntu12.04 具体环境搭建过程,可以向客服索要用户手册!上面有非常详细的过程! 2.2 准备工作 再下载.配置.编译openwrt系统之前,我们需要做些准备工作,安装一些必须的工具.库. (1) 安装SVN工具 安装SVN工具,用于下载openwrt源码: $ sudo apt-ge

阿里云弹性计算服务ECS基本概念(第二章)

第二章:弹性计算服务ECS基本概念四.ECS产品概念ECS,是由多个并列,又相互关联的产品概念组成,包括在介绍产品概念之前,先需要理解两个重要的逻辑位置概念Region,地域,是阿里云提供云计算服务的城市位置.一般一个Region会覆盖一片区域,如北京地域覆盖华北区域Zone,可用区,是一个Region下,电力和网络独立,软件故障隔离的物理数据中心.可用区的开放,目的是容许用户自行选择资源的分配策略如何选择Rgion和ZoneECS产品概念之间的关系五.ECS实例介绍ECS实例概念与实例规格实例

Unity 游戏框架搭建 2019 (九~十二) 第一章小结&amp;第二章简介&amp;第八个示例

第一章小结 为了强化教程的重点,会在合适的时候进行总结与快速复习. 第二章 简介 在第一章我们做了知识库的准备,从而让我们更高效地收集示例. 在第二章,我们就用准备好的导出工具试着收集几个示例,这些示例中有的是我们后续库的基础工具,也有的是在项目中非常实用的小工具,还有一些示例是实践了在框架搭建方向上非常重要的 C# 语法知识. 第二章大纲如下. 第八个示例(一) 在之前,我们完成了一个导出的功能.但是在完成这个功能的过程中,我们也遇到了一些问题.我们回忆一下,在<MenuItem 复用>的这

第二章 有什么理由使用Async异步编程

p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提高下英文,用我拙劣的英文翻译一些重要的部分,纯属娱乐,简单分享,保持学习,谨记谦虚. 如果你觉得这件事儿没意义翻译的又差,尽情的踩吧.如果你觉得值得鼓励,感谢留下你的赞,在今后每一次应该猛烈突破的时候,不选择知难而退.在每一次应该独立思考的时候,不选择随波逐流,应该全力以赴的时候,不选择尽力而为,愿爱技术的园

Prism 文档 第二章 初始化Prism应用程序

                                                                       第二章 初始化Prism应用程序 本章将讨论为了使一个Prism应用程序的启动和运行哪些是必须的.Prism的应用程序在启动过程中需要注册和配置,这被称为引导应用程序. 什么是Bootstrapper? bootstrapper是一个类,通过Prism类库负责一个应用程序建立的初始化.通过使用bootstrapper,对于如何将Prism库组件连接到您的应