zoukankan      html  css  js  c++  java
  • 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[]类型 。
    image
    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<stringobject> 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. 引用服务初始化连接程序
    clip_image004

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

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

    image

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

    b). Silverlight的几何图形类型与空间数据类型有很多相似的地方,但是对于MultiPolygon等类型就很难处理了,没有匹配的类型去实现它。
    下图显示了 MultiPolygon 实例的示例。
    clip_image008
    图 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)为顶点的三角形内环。
    clip_image010
    虽然一个Path对应数据库一条记录,即一个空间图形实例,但是在逻辑上我们尽量让用于显示的图形实例趋于独立,即一个MultiPolygon还是分成多个Path,而不是用一个Pathd对象来表示,这样方便程序后期维护,因为需求可能会对子区域再做单独处理。
    c). 数据模型视图
    image

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

    image

    3. 数据模型的产生过程:
    clip_image016

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

    代码
    /// <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>

    最后上一下效果图
    image

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

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

  • 相关阅读:
    动态生成 Excel 文件供浏览器下载的注意事项
    JavaEE 中无用技术之 JNDI
    CSDN 泄露用户密码给我们什么启示
    刚发布新的 web 单点登录系统,欢迎下载试用,欢迎提建议
    jQuery jqgrid 对含特殊字符 json 数据的 Java 处理方法
    一个 SQL 同时验证帐号是否存在、密码是否正确
    PostgreSQL 数据库在 Windows Server 2008 上安装注意事项
    快速点评 Spring Struts Hibernate
    Apache NIO 框架 Mina 使用中出现 too many open files 问题的解决办法
    解决 jQuery 版本升级过程中出现 toLowerCase 错误 更改 doctype
  • 原文地址:https://www.cnblogs.com/ysisl/p/1662201.html
Copyright © 2011-2022 走看看