轉(zhuǎn)帖|其它|編輯:郝浩|2011-01-13 15:05:23.000|閱讀 848 次
概述:GeoServer 是 OpenGIS Web 服務(wù)器規(guī)范的 J2EE 實現(xiàn)的社區(qū)開源項目,利用 GeoServer 可以方便的發(fā)布地圖數(shù)據(jù),允許用戶對特征數(shù)據(jù)進行更新、刪除、插入操作,通過 GeoServer 可以比較容易的在用戶之間迅速共享空間地理信息。本系列博文提供全面、完善的GeoServer部署解決方案,包括GeoServer環(huán)境搭建、地圖數(shù)據(jù)處理、部署地圖數(shù)據(jù)、發(fā)布地圖服務(wù)等功能的詳細(xì)介紹。文中內(nèi)容來自本人工作中通過網(wǎng)絡(luò)學(xué)習(xí)后總結(jié)而成,如有類同純屬巧合,同時歡迎廣大網(wǎng)友前來交流。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
GeoServer 是 OpenGIS Web 服務(wù)器規(guī)范的 J2EE 實現(xiàn)的社區(qū)開源項目,利用 GeoServer 可以方便的發(fā)布地圖數(shù)據(jù),允許用戶對特征數(shù)據(jù)進行更新、刪除、插入操作,通過 GeoServer 可以比較容易的在用戶之間迅速共享空間地理信息。本系列博文提供全面、完善的GeoServer部署解決方案,包括GeoServer環(huán)境搭建、地圖數(shù)據(jù)處理、部署地圖數(shù)據(jù)、發(fā)布地圖服務(wù)等功能的詳細(xì)介紹。文中內(nèi)容來自本人工作中通過網(wǎng)絡(luò)學(xué)習(xí)后總結(jié)而成,如有類同純屬巧合,同時歡迎廣大網(wǎng)友前來交流。
我曾經(jīng)寫作過一篇關(guān)于微軟Bing Maps的客戶端實現(xiàn)的博文:《基于DeepZoom技術(shù)的Bing Maps客戶端實現(xiàn)研究》,詳細(xì)介紹了如何使用Silverlight中的DeepZoom技術(shù)實現(xiàn)Bing Maps的客戶端。本篇介紹的內(nèi)容則為基于Web地圖服務(wù)(Web Map Service,簡稱:WMS)的Silverlight地圖客戶端實現(xiàn)。
一、DeepZoom簡介
DeepZoom技術(shù)以MultiScaleImage控件為核心,其內(nèi)部有一個MultiScaleTileSource類型的源屬性,主要用于設(shè)置MultiScaleImage控件所要呈現(xiàn)的數(shù)據(jù)源。基于Silverlight的Web GIS客戶端實現(xiàn)也是通MultiScaleImage控件來實現(xiàn),核心就在于通過MultiScaleTileSource屬性針對不同的Web GIS地圖瓦片數(shù)據(jù)(Image Tiles)提供商為MultiScaleImage控件實現(xiàn)一個數(shù)據(jù)源。因此本篇所需要做的工作就是針對WMS服務(wù)為MultiScaleImage控件實現(xiàn)一套加載數(shù)據(jù)源的算法。
二、WMS服務(wù)加載實現(xiàn)
實現(xiàn)WMS服務(wù)加載的算法其實非常簡單,只需要了解WMS發(fā)布的方式、WMS地址的參數(shù)組成結(jié)構(gòu)以及地圖瓦片的投影原理就可以了,首先需要定義一個盒子對象作為訪問WMS的邊界參數(shù)對象。
public class BBox
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public BBox(int x, int y, int w, int h)
{
this.X = x;
this.Y = y;
this.Width = w;
this.Height = h;
}
} public class WMSTileSource : MultiScaleTileSource
{
public WMSTileSource()
: base(int.MaxValue, int.MaxValue, 0x100, 0x100, 0)
{ }
public const int TILE_SIZE = 256;
/// <summary>
/// 地球半徑
/// </summary>
public const double EARTH_RADIUS = 6378137;
/// <summary>
/// 地球周長
/// </summary>
public const double EARTH_CIRCUMFERENCE = EARTH_RADIUS * 2 * Math.PI;
public const double HALF_EARTH_CIRCUMFERENCE =
EARTH_CIRCUMFERENCE / 2;
/// <summary>
/// WMS服務(wù)地址
/// </summary>
private const string TilePath = @ "//localhost:8080/geoserver/wms?service=WMS&version=1.1.0&request=
GetMap&layers=cq:CQ_County_region,cq:CQ_County_region_level&styles=
&bbox={0},{1},{2},{3}&width=512&height=421&srs=
EPSG:4326&&Format=image/png";
public string GetQuadKey(string url)
{
var regex = new Regex( ".*tiles/(.+)[.].*");
Match match = regex.Match(url);
return match.Groups[1].ToString();
}
public BBox QuadKeyToBBox(string quadKey, int x, int y, int zoomLevel)
{
char c = quadKey[0];
int tileSize = 2 << (18 - zoomLevel - 1);
if (c == '0')
{
y = y - tileSize;
}
else if (c == '1')
{
y = y - tileSize;
x = x + tileSize;
}
else if (c == '3')
{
x = x + tileSize;
}
if (quadKey.Length > 1)
{
return QuadKeyToBBox(quadKey.Substring(1), x, y, zoomLevel + 1);
}
return new BBox(x, y, tileSize, tileSize);
}
public BBox QuadKeyToBBox(string quadKey)
{
const int x = 0;
const int y = 262144;
return QuadKeyToBBox(quadKey, x, y, 1);
}
public double XToLongitudeAtZoom(int x, int zoom)
{
double arc = EARTH_CIRCUMFERENCE / ((1 << zoom) * TILE_SIZE);
double metersX = (x * arc) - HALF_EARTH_CIRCUMFERENCE;
double result = RadToDeg(metersX / EARTH_RADIUS);
return result;
}
public double YToLatitudeAtZoom(int y, int zoom)
{
double arc = EARTH_CIRCUMFERENCE / ((1 << zoom) * TILE_SIZE);
double metersY = HALF_EARTH_CIRCUMFERENCE - (y * arc);
double a = Math.Exp(metersY * 2 / EARTH_RADIUS);
double result = RadToDeg(Math.Asin((a - 1) / (a + 1)));
return result;
}
public double RadToDeg(double d)
{
return d / Math.PI * 180.0;
}
private static string TileXYToQuadKey(int tileX, int tileY, int levelOfDetail)
{
var quadKey = new StringBuilder();
for (int i = levelOfDetail; i > 0; i--)
{
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0)
{
digit++;
}
if ((tileY & mask) != 0)
{
digit++;
digit++;
}
quadKey.Append(digit);
}
return quadKey.ToString();
}
protected override void GetTileLayers(int tileLevel, int tilePositionX, int tilePositionY, System.Collections.Generic.IList <object> tileImageLayerSources)
{
int zoom = tileLevel - 8;
if (zoom > 0)
{
string quadKey = TileXYToQuadKey(tilePositionX, tilePositionY, zoom);
BBox boundingBox = QuadKeyToBBox(quadKey);
double lon = XToLongitudeAtZoom(boundingBox.X * TILE_SIZE, 18);
double lat = YToLatitudeAtZoom(boundingBox.Y * TILE_SIZE, 18);
double lon2 =
XToLongitudeAtZoom((boundingBox.X + boundingBox.Width) * TILE_SIZE, 18);
double lat2 =
YToLatitudeAtZoom((boundingBox.Y - boundingBox.Height) * TILE_SIZE, 18);
string wmsUrl = string.Format(TilePath, lon, lat, lon2, lat2, TILE_SIZE);
var veUri = new Uri(wmsUrl);
tileImageLayerSources.Add(veUri);
}
}
}
前端通過一個按鈕事件驅(qū)動觸發(fā)加載WMS服務(wù),按鈕的XAML代碼如下:
<Button Content="WMS圖層" Height="30" Width=
"80" Name="btnWms" Click="btnWms_Click"/>
示例我就直接基于《基于DeepZoom技術(shù)的Bing Maps客戶端實現(xiàn)研究》一文中的示例擴展,對應(yīng)的后臺代碼為如下代碼塊:
private void btnWms_Click(object sender, RoutedEventArgs e)
{
msi.Source = new WMSTileSource();
}
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載