博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GeoServer地图开发解决方案(五):基于Silverlight技术的地图客户端实现
阅读量:7260 次
发布时间:2019-06-29

本文共 4678 字,大约阅读时间需要 15 分钟。

 GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现的社区开源项目,利用 GeoServer 可以方便的发布地图数据,允许用户对特征数据进行更新、删除、插入操作,通过 GeoServer 可以比较容易的在用户之间迅速共享空间地理信息。本系列博文提供全面、完善的GeoServer部署解决方案,包括GeoServer环境搭建、地图数据处理、部署地图数据、发布地图服务等功能的详细介绍。文中内容来自本人工作中通过网络学习后总结而成,如有类同纯属巧合,同时欢迎广大网友前来交流。  

          

        

  系列目录导航:

  

  

  

  

  

 

  我曾经写作过一篇关于微软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"
/>

 

  示例我就直接基于《》一文中的示例扩展,对应的后台代码为如下代码块:

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

 

         

 

     

本文转自 beniao 51CTO博客,原文链接:http://blog.51cto.com/beniao/478333,如需转载请自行联系原作者
你可能感兴趣的文章
Sublime Text 3 全套快捷键及功能介绍
查看>>
1.01 与 37.8
查看>>
centOS6.7 /etc/profile
查看>>
理一理Latency、Bandwidth、Throughput、Response Time概念的区别
查看>>
关于“习惯”的精彩分析
查看>>
Android activity 参数传递
查看>>
雷观(十五):提高生产力和程序员价值的2种方法
查看>>
记一次validator jar冲突导致的启动异常
查看>>
View和ViewGroup常用方法
查看>>
烂泥:【解决】VMware Workstation中安装ESXI5.0双网卡问题
查看>>
【OpenCV笔记】图像预处理
查看>>
如何添加和删除LaunchPad里面的程序图标
查看>>
iOS 7 Searchbar右侧空白
查看>>
iOS App Launch Option
查看>>
Apache Traffic Server处理请求的过程
查看>>
域名解析的记录类型区别
查看>>
为女儿取名“王者荣耀”可想过代价?
查看>>
iPhone X掉漆愈演愈烈?手机变成刮刮乐
查看>>
dubbo+zookeeper+dubbo管理控制台实践demo
查看>>
【iOS】【项目全局动态埋点】Runtime+Aspects(hook)
查看>>