第一步构建下载数据源的描述文件
如此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)