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 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;
    }
}

  关于WMS服务加载的详细算法需要一些GIS理论基础才能够知道具体的实现原理,这里我就不逐一介绍,直接贴代码:

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服务地址
    /// </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代码如下:

<Button Content="WMS图层" Height="30" Width="80" Name="btnWms" Click="btnWms_Click"/>

  示例我就直接基于《基于DeepZoom技术的Bing Maps客户端实现研究》一文中的示例扩展,对应的后台代码为如下代码块:

private void btnWms_Click(object sender, RoutedEventArgs e)
{
    msi.Source = new WMSTileSource();
}

        

    

GeoServer地图开发解决方案(五):基于Silverlight技术的地图客户端实现相关推荐

  1. GeoServer地图开发解决方案(三):部署地图数据篇

    GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...

  2. 【转】GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇

    GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...

  3. GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇

    GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...

  4. GeoServer地图开发解决方案

    GeoServer地图开发解决方案(一):环境搭建篇 GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许 ...

  5. wms地图绘制工具_GeoServer地图开发解决方案(四):发布Web地图服务(WMS)篇

    GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新.删除.插入操作,通过 GeoS ...

  6. echarts地图文字重叠解决方案_基于Echarts的百度地图叠加arcgis server的WMS图层服务...

    前言 前阵子利用echarts+百度地图做系统的门户首页,遇到一个要地图上叠加产业城影响范围示意图的需求.查阅文档之后,发现百度地图API确实提供了叠加自定义图层的方法,详情请看: 百度地图API的M ...

  7. android 百度地图开发 别人用不了,Android百度地图开发的那些不足之处

    Android百度地图开发的那些不足之处,最近做的项目中百度地图是很重要的一个模块,其中实现了定位.自定义Marker图标.线路规划.SuggestionSearch检索.地图截图以及导航等功能.因为 ...

  8. html5地图连线原理,基于html5技术绘制上海地铁图 – 双车道路况信息

    上海地铁图的绘制,最近有客户提出了新的需求:双车道,并显示路网状态信息.经过一番研究,在原地铁图基础上做了扩展实现 交通图介绍 路况状态在GIS系统中广泛应用,谷歌地图,百度地图都有实时路况的功能,太 ...

  9. 百度地图开发(五)之公交信息检索 + 路线规划

    转载请注明出处:http://blog.csdn.net/crazy1235/article/details/44069267 在上一篇blog中介绍过POI检索的使用,本篇blog主要介绍公交信息检 ...

  10. 智慧园区地图导航解决方案,如何实现园区内地图导航?

    智慧园区解决方案面向于产业园区.根据智能化系统.信息化管理方式与技术,根据设备网.互联网技术.物联网技术,从数据园区转为智慧园区.三维GIS平台的智慧园区建设主要目标是为用户提供高效.便捷.舒适.生态 ...

最新文章

  1. 是什么使你留在你的公司
  2. Windows Sockets错误标识及对应解释
  3. 关于silverlight+MVVM+WCF保存数据出错的问题
  4. IBatis.Net学习笔记五--常用的查询方式
  5. 让数据中台飞起来—— Quick BI性能优化解决方案及实践
  6. 如何安装和使用纯文本编辑器 vi/vim
  7. 计算机网路网络层之DHCP协议
  8. etcdctl的使用
  9. 绘制北京市蜜雪冰城门店地图
  10. 如何让excel说话,vba的speak功能
  11. vue移动端点击事件延迟_如何解决移动端Click事件300ms延迟的问题?
  12. 开环传递函数判断系统类型_已知系统的开环传递函数,试用Nyquist稳定判据判断系统的稳定性。_学小易找答案...
  13. 普通最小二乘法讲解OLS线性回归
  14. 从前后端分离到前后端整合的“退步”(二)pom.xml文件配置
  15. 局部边缘保持滤波(LEP)高动态范围图像HDR压缩 matlab程序(一)
  16. canvas绘制火柴人
  17. 计算机二级网上报名2019安徽,2019年上半年安徽计算机二级考试报名时间
  18. 作为前端,如何帮帝都的朋友租到合适的房子
  19. x264源代码简单分析:编码器主干部分-1
  20. fhq treap入门

热门文章

  1. matlab中global
  2. html ckplayer.swf,Flash基础入门之ckplayer.js视频播放插件
  3. 英文学术论文写作基础
  4. 前端开发和后端开发究竟有什么区别?详细介绍
  5. 哪些人需要在三九天调理体质?什么情况需要泡三九药浴?
  6. HTML5表单技术 调查问卷设计
  7. 让电脑假装蓝屏的C语言,假装电脑坏了 一键让电脑进入蓝屏或重装系统界面方法...
  8. python儿童编程入门-如何让孩子轻松学习Python编程
  9. 儿童python编程教程-一款儿童编程入门的理想工具——PythonTurtle
  10. 如何用SPSS对数据进行标准化处理?