Silverlight Map 矢量地图构建过程分析

本文主要结合SQLSERVER2008的空间数据库的一些特性,讲解Silverlight在矢量地图绘制方面的一些技术点。服务器端负责提供数据服务,客户端负责图形的绘制,当然这个过程会遇到性能瓶颈,但本文的重点在于地图数据模型的转化过程,以及Silverlight的数据绑定与数据模型间的关系的理解。

 

服务器端

数据模型层:

1. 获取原始数据模型
从SQLSERVER2008取得数据集DataSet,其中包含的几何数据类型Geometry在.NetCLR中被映射为SqlGeometry类型,该类型在程序集Microsoft.SqlServer.Types.dll的Microsoft.SqlServer.Types 命名空间下(该程序集由SQLSERVER2008自带)。

2. 封装成可序列化的用户数据模型 :GeometryFeature
 遍历DataSet,除SqlGeometry类型外,其余数据保存在以字典Dictionary<string,object>中,Key为字段名,Value为值。SqlGeometry数据由类型自带的STAsBinary()函数转化为byte[]类型 。
Silverlight Map 矢量地图构建过程分析_第1张图片
GometryFeature申明为指定序列化或反序列化时Web服务能够使用的识别的已知类型。

 

代码
    [DataContract(IsReference  =   true ), ServiceKnownType( typeof (GeometryFeature))]
    
public   class  GeometryFeature
    {
        
public  GeometryFeature()
        { 
        }

        
public  GeometryFeature( byte [] bytes, Dictionary < string , object >  attributes)
        {
            
this .BinaryGeometry  =  bytes;
            
this .Attributes  =  attributes;
        }

        [DataMember]
        
public  Dictionary < string object >  Attributes
        {
            
get ;
            
set ;
        }

        [DataMember]
        
public   byte [] BinaryGeometry
        {

            
get ;
            
set ;
        }
    }

 

服务层

使用WCF服务发布数据

代码
namespace  WebMap.Web
{
    [ServiceContract(Namespace 
=   "" )]
    [AspNetCompatibilityRequirements(RequirementsMode 
=  AspNetCompatibilityRequirementsMode.Allowed)]
    
public   class  MapService
    {
        [OperationContract]
        
public  List < GeometryFeature >  GetMap()
        {
            
//  Add your operation implementation here
             return  MapDataService.GetGeometryFeature();
        }
        [OperationContract]
        
public   bool  UpdateAttributes(Dictionary < string , object >  attributes)
        {
            
return  MapDataService.UpdateFields(attributes);
        }
        
//  Add more operations here and mark them with [OperationContract]
    }
}

 
客户端

1. 引用服务初始化连接程序
Silverlight Map 矢量地图构建过程分析_第2张图片

引用完成后在MapService下有自动生成的Reference.cs类,其中生成了我们在服务器端定义的GeometryFeature数据模型。

2. 客户端几何数据模型
但这只是基于网络传输的二进制数据模型,我们需要把它还原成Geometry类型,当然这种Geometry类型微软没有提供Silverlight版本的,所以目前为止还只能自己写。但网络上有很多现成的开源项目,如SharpMap,SharpGIS,许多底层的像数据库几何类型的二进制码读取,类型识别,等等操作已经写好,可以重用这些类库。我在此基础上改写了SharpGIS的库,并添加了用于Silverlight数据绑定的ViewModel。

Silverlight Map 矢量地图构建过程分析_第3张图片

这里需要说明一些基本的概念:
a). 空间数据库中读取的几何数据类型有下面几种(蓝色表示):
Silverlight Map 矢量地图构建过程分析_第4张图片
这些类型在SharpGIS.Geometries命名空间下都已经实现,SharpMap的Geometry实现更为强大,没有时间仔细研究,相比之下SharpGIS的结构更容易理解,做小项目也够用了。

b). Silverlight的几何图形类型与空间数据类型有很多相似的地方,但是对于MultiPolygon等类型就很难处理了,没有匹配的类型去实现它。
下图显示了 MultiPolygon 实例的示例。
Silverlight Map 矢量地图构建过程分析_第5张图片
图 1 是一个包含两个 Polygon 元素的 MultiPolygon 实例。边界由两个外环和三个内环界定。
图 2 是一个包含两个 Polygon 元素的 MultiPolygon 实例。边界由两个外环和三个内环界定。这两个 Polygon 元素在切点处相交。

这样的图形在空间数据库中只用一条记录就可以保存,但是在客户端程序中大多数使用传统GDI+控制显示,会显得异常复杂。而Silverlight在这方面却有着得天独厚的优势,最大的优势就在于引入了功能强大、用法复杂的 mini-language 来描述可扩展应用程序标记语言 (XAML) 中的几何路径,可以像空间数据库一样使用字符串微命令构建任意形状的图形,关于路径标记语法,这里只做简单介绍:
<Path Fill=”Black” Data=” M 0,0 100,0 100,100 M 10,3 50,10 50,45 Z" />
仅这样一个XAML语句就可以绘出一个以(0,0) (100,0) (100,100)为顶点的三角形外环和一个以(10,2) (50,10) (50,45)为顶点的三角形内环。
Silverlight Map 矢量地图构建过程分析_第6张图片
虽然一个Path对应数据库一条记录,即一个空间图形实例,但是在逻辑上我们尽量让用于显示的图形实例趋于独立,即一个MultiPolygon还是分成多个Path,而不是用一个Pathd对象来表示,这样方便程序后期维护,因为需求可能会对子区域再做单独处理。
c). 数据模型视图
Silverlight Map 矢量地图构建过程分析_第7张图片

在数据的组织结构上,MapRegion是一个图形实例的数据容器:里面包含了所有从Attributes中获取的实例属性,如FillColor、LineColor、Label等,而这些属性都注册成依赖属性,以方便视图绑定时用。图形数据存储在(MapRegion.Geometries[0]).(MapPath.PathData)中。

Silverlight Map 矢量地图构建过程分析_第8张图片

3. 数据模型的产生过程:
Silverlight Map 矢量地图构建过程分析_第9张图片

客户端接收服务数据后的回调函数:

代码
///   <summary>  
///  接收数据完成,回调函数 
///   </summary>  
///   <param name="sender"></param>  
///   <param name="e"></param>  
void  client_GetMapCompleted( object  sender, GetMapCompletedEventArgs e) 

     List
< Feature >  features  =   new  List < Feature > (e.Result.Count); 
     
foreach (var geomFeature  in  e.Result) 
     { 
        Feature f 
=   new  Feature(); 
        f.Attributes 
=  geomFeature.Attributes; 
        f.Geometry 
=  ( new  Wkb()).Read(geomFeature.BinaryGeometry); 
        features.Add(f); 
        GeographysCoordinateConvertor.JoinMap(f.Geometry); 
        
// 计算整个地图区域的最大矩形包络 
      } 
     visualMap.ShowMap(features, 
false );
 
}

 
到此为止MapRegion与服务器数据模型只是在数据结构上做了转化,是一一对应的关系。
而MapRegion如果对应着MultiPolygon类型的数据,则在此就要开始分解,所以MapRegion内部属性Geometries 就是用来保存MultiPolygon的子图形,为了绑定方便,即便不是复合类型的图形,也会默认将图形的PathData填充到Geometries[0]中。
由Feature到MapRegion构建的过程就不贴出来了。只是在这个过程中构建PathData路径时要注意将经纬度转换为相对于当前Canvas的相对坐标,关于坐标转换,在上一篇中已经讲过,原理是一样的。

4.  客户端XAML视图
利用Canvas做主容器,ItemsControl布置图形排列(使用Canvas做为ItemPanel可以继承父Canvas的相对布局位置)。
数据模板最好自定义一个用户控件,最后绑定好顶级Canvas的上下文环境为Map类型的数据容器,Silverlight就会自动呈现所有图形及绑定。

项容器面板和数据模板的定义

代码
 1  < ItemsPanelTemplate  x:Key ="SimpleCanvasTemplate" >  
 2 
 3  < Canvas  x:Name ="ContainingCanvas"   />  
 4 
 5  </ ItemsPanelTemplate >  
 6 
 7  <!-- 标签项模板 -->  
 8 
 9  < DataTemplate  x:Key ="LabelItemTemplate" >  
10 
11  < Canvas >  
12 
13  < TextBlock  x:Name ="LabelTxt"  Canvas.Left =" {Binding Region.Center.X} "  Canvas.Top =" {Binding Region.Center.Y} "  Text =" {Binding Region.Label} "  TextWrapping ="Wrap" />  
14 
15  </ Canvas >  
16 
17  </ DataTemplate >  
18 
19  <!-- 标签层模板 -->  
20 
21  < DataTemplate  x:Key ="LabelLayerTemplate" >  
22 
23  < ItemsControl  ItemsPanel =" {StaticResource SimpleCanvasTemplate} "  ItemTemplate =" {StaticResource LabelItemTemplate} "  ItemsSource =" {Binding Geometries} "  Tag =" {Binding} "   />  
24 
25  </ DataTemplate >  
26 
27  <!-- 图形模板 -->  
28 
29  < DataTemplate  x:Key ="PolygonTemplate" >  
30 
31  < local:GeometryPathTemplate  MouseEnter ="Polygon_MouseEnter"  GeometryMouseLeave ="Polygon_MouseLeave"  Selected =" {Binding Region.IsSelected} "  
32 
33  MouseLeftButtonDown ="DefaultPolygonStyle_MouseLeftButtonDown"  MouseLeave ="Polygon_MouseLeave"   />  
34 
35  </ DataTemplate >  
36 
37  <!-- 图形层模板 -->  
38 
39  < DataTemplate  x:Key ="RegionTemplate" >  
40 
41  < ItemsControl  ItemsPanel =" {StaticResource SimpleCanvasTemplate} "  ItemTemplate =" {StaticResource PolygonTemplate} "  ItemsSource =" {Binding Geometries} "   />   </ DataTemplate >
42 
43 
44 
45 

 

Path控件模板

代码
< UserControl
    
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable
="d"
    x:Class
="WebMap.GeometryPathTemplate"
    d:DesignWidth
="640"  d:DesignHeight ="480"  Clip =" {Binding PathData} " >


        
< Path  x:Name ="GeometryPathShape"  Cursor ="Hand"  StrokeLineJoin ="Round"   Data =" {Binding PathData} "  
                        Fill
=" {Binding Region.FillColor} "
                        Stroke
=" {Binding Region.LineColor} "
                        StrokeThickness
=" {Binding Region.LineThickness} "  
                         
/>
 
</ UserControl >

 

最后上一下效果图
Silverlight Map 矢量地图构建过程分析_第10张图片

 

这是一个不算完整的项目,重点讲述一些Silverlight在矢量地图显示方面的技术,很多细节没有展开。当然,这些只是个人体会,至于Morten Nielsen这样的大牛们是否会这样去设计,只有等待SharpMap的Silverlight版本出来时才能一睹设计师的风采了。

 

 

作者:双宇
出处:http://www.cnblogs.com/ysisl

你可能感兴趣的:(Silverlight Map 矢量地图构建过程分析)