GeoServer地图开发解决方案(五):基于Silverlight技术的地图客户端实现
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新、删除、插入操作,通过 GeoServer 可以比较容易的在用户之间迅速共享空间地理信息。本系列博文提供全面、完善的GeoServer部署解决方案,包括GeoServer环境搭建、地图数据处理、部署地图数据、发布地图服务等功能的详细介绍。文中内容来自本人工作中通过网络学习后总结而成,如有类同纯属巧合,同时欢迎广大网友前来交流。
系列目录导航:
GeoServer地图开发解决方案(一):环境搭建篇
GeoServer地图开发解决方案(二):地图数据处理篇
GeoServer地图开发解决方案(三):部署地图数据篇
GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇
GeoServer地图开发解决方案(五):基于Silverlight技术的地图客户端实现
我曾经写作过一篇关于微软Bing Maps的客户端实现的博文:《基于DeepZoom技术的Bing Maps客户端实现研究》,详细介绍了如何使用Silverlight中的DeepZoom技术实现Bing Maps的客户端。本篇介绍的内容则为基于Web地图服务(Web Map Service,简称:WMS)的Silverlight地图客户端实现。
一、DeepZoom简介
DeepZoom技术以MultiScaleImage控件为核心,其内部有一个MultiScaleTileSource类型的源属性,主要用于设置MultiScaleImage控件所要呈现的数据源。基于Silverlight的Web GIS客户端实现也是通MultiScaleImage控件来实现,核心就在于通过MultiScaleTileSource属性针对不同的Web GIS地图瓦片数据(Image Tiles)提供商为MultiScaleImage控件实现一个数据源。因此本篇所需要做的工作就是针对WMS服务为MultiScaleImage控件实现一套加载数据源的算法。
二、WMS服务加载实现
实现WMS服务加载的算法其实非常简单,只需要了解WMS发布的方式、WMS地址的参数组成结构以及地图瓦片的投影原理就可以了,首先需要定义一个盒子对象作为访问WMS的边界参数对象。
{
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;
}
}
关于WMS服务加载的详细算法需要一些GIS理论基础才能够知道具体的实现原理,这里我就不逐一介绍,直接贴代码:
{
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服务地址
/// </summary>
private const string TilePath = @"http://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);
}
}
}
前端通过一个按钮事件驱动触发加载WMS服务,按钮的XAML代码如下:
示例我就直接基于《基于DeepZoom技术的Bing Maps客户端实现研究》一文中的示例扩展,对应的后台代码为如下代码块:
{
msi.Source = new WMSTileSource();
}
GeoServer地图开发解决方案(五):基于Silverlight技术的地图客户端实现相关推荐
- GeoServer地图开发解决方案(三):部署地图数据篇
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...
- 【转】GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...
- GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...
- GeoServer地图开发解决方案
GeoServer地图开发解决方案(一):环境搭建篇 GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许 ...
- wms地图绘制工具_GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇
GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...
- echarts地图文字重叠解决方案_基于Echarts的百度地图叠加arcgis server的WMS图层服务...
前言 前阵子利用echarts+百度地图做系统的门户首页,遇到一个要地图上叠加产业城影响范围示意图的需求.查阅文档之后,发现百度地图API确实提供了叠加自定义图层的方法,详情请看: 百度地图API的M ...
- android 百度地图开发 别人用不了,Android百度地图开发的那些不足之处
Android百度地图开发的那些不足之处,最近做的项目中百度地图是很重要的一个模块,其中实现了定位.自定义Marker图标.线路规划.SuggestionSearch检索.地图截图以及导航等功能.因为 ...
- html5地图连线原理,基于html5技术绘制上海地铁图 – 双车道路况信息
上海地铁图的绘制,最近有客户提出了新的需求:双车道,并显示路网状态信息.经过一番研究,在原地铁图基础上做了扩展实现 交通图介绍 路况状态在GIS系统中广泛应用,谷歌地图,百度地图都有实时路况的功能,太 ...
- 百度地图开发(五)之公交信息检索 + 路线规划
转载请注明出处:http://blog.csdn.net/crazy1235/article/details/44069267 在上一篇blog中介绍过POI检索的使用,本篇blog主要介绍公交信息检 ...
- 智慧园区地图导航解决方案,如何实现园区内地图导航?
智慧园区解决方案面向于产业园区.根据智能化系统.信息化管理方式与技术,根据设备网.互联网技术.物联网技术,从数据园区转为智慧园区.三维GIS平台的智慧园区建设主要目标是为用户提供高效.便捷.舒适.生态 ...
最新文章
- 是什么使你留在你的公司
- Windows Sockets错误标识及对应解释
- 关于silverlight+MVVM+WCF保存数据出错的问题
- IBatis.Net学习笔记五--常用的查询方式
- 让数据中台飞起来—— Quick BI性能优化解决方案及实践
- 如何安装和使用纯文本编辑器 vi/vim
- 计算机网路网络层之DHCP协议
- etcdctl的使用
- 绘制北京市蜜雪冰城门店地图
- 如何让excel说话,vba的speak功能
- vue移动端点击事件延迟_如何解决移动端Click事件300ms延迟的问题?
- 开环传递函数判断系统类型_已知系统的开环传递函数,试用Nyquist稳定判据判断系统的稳定性。_学小易找答案...
- 普通最小二乘法讲解OLS线性回归
- 从前后端分离到前后端整合的“退步”(二)pom.xml文件配置
- 局部边缘保持滤波(LEP)高动态范围图像HDR压缩 matlab程序(一)
- canvas绘制火柴人
- 计算机二级网上报名2019安徽,2019年上半年安徽计算机二级考试报名时间
- 作为前端,如何帮帝都的朋友租到合适的房子
- x264源代码简单分析:编码器主干部分-1
- fhq treap入门
热门文章
- matlab中global
- html ckplayer.swf,Flash基础入门之ckplayer.js视频播放插件
- 英文学术论文写作基础
- 前端开发和后端开发究竟有什么区别?详细介绍
- 哪些人需要在三九天调理体质?什么情况需要泡三九药浴?
- HTML5表单技术 调查问卷设计
- 让电脑假装蓝屏的C语言,假装电脑坏了 一键让电脑进入蓝屏或重装系统界面方法...
- python儿童编程入门-如何让孩子轻松学习Python编程
- 儿童python编程教程-一款儿童编程入门的理想工具——PythonTurtle
- 如何用SPSS对数据进行标准化处理?