西南大学校园GIS平台

系统架构是B/S,开发语言是C#、silverlight,开发平台是.NET,数据库为sqlserver,这是我读研究生时候自己做的作品,以自己的母校为地图,进行GIS相关的功能分析,核心的模块有:空间查询、GPS定位模拟、搜索模块、统计分析;其中说的不足之处,望各位指点出来。

**一、空间查询 **

整体思路:空间查询是用户在地图上框选一定范围,然后根据框选范围Geometry来进行query查询。框选利用Draw工具有多边形、矩形、圆线等方式。实现方式,前台界面设计:

<pre>

<Grid x:Name="ToolbarGrid" HorizontalAlignment="Left" VerticalAlignment="Top" Width="600" Height="0" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<ScaleTransform x:Name="ToolbarGridScaleTransform" ScaleX="0" ScaleY="0" />
</Grid.RenderTransform>
<StackPanel Orientation="Vertical">
<esriToolkit:Toolbar x:Name="MyToolbar" MaxItemHeight="40" MaxItemWidth="40"
VerticalAlignment="Top" HorizontalAlignment="Left"
Loaded="MyToolbar_Loaded"
ToolbarItemClicked="MyToolbar_ToolbarItemClicked"
ToolbarIndexChanged="MyToolbar_ToolbarIndexChanged"
Width="600" Height="40">
<esriToolkit:Toolbar.Items>
<esriToolkit:ToolbarItemCollection>

<esriToolkit:ToolbarItem Text="放大">
<esriToolkit:ToolbarItem.Content>
<Image Source="Images/i_zoomin.png" Stretch="UniformToFill" Margin="3" />
</esriToolkit:ToolbarItem.Content>
</esriToolkit:ToolbarItem>

<esriToolkit:ToolbarItem Text="缩小">
<esriToolkit:ToolbarItem.Content>
<Image Source="Images/i_zoomout.png" Stretch="UniformToFill" Margin="3" />
</esriToolkit:ToolbarItem.Content>
</esriToolkit:ToolbarItem>

<esriToolkit:ToolbarItem Text="多边形查询">
<esriToolkit:ToolbarItem.Content>
<Image Source="Images/DrawPolygon.png" Stretch="UniformToFill" Margin="5"/>
</esriToolkit:ToolbarItem.Content>
</esriToolkit:ToolbarItem>

<esriToolkit:ToolbarItem Text="线查询">
<esriToolkit:ToolbarItem.Content>
<Image Source="Images/DrawPolyline.png" Stretch="UniformToFill" Margin="5"/>
</esriToolkit:ToolbarItem.Content>
</esriToolkit:ToolbarItem>

<esriToolkit:ToolbarItem Text="矩形查询">
<esriToolkit:ToolbarItem.Content>
<Image Source="Images/DrawRectangle.png" Stretch="UniformToFill" Margin="5"/>
</esriToolkit:ToolbarItem.Content>
</esriToolkit:ToolbarItem>
</esriToolkit:ToolbarItemCollection>
</esriToolkit:Toolbar.Items>
</esriToolkit:Toolbar>
<TextBlock x:Name="StatusTextBlock" FontWeight="Bold" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>

     这里只讲空间查询部分,其他的距离量算、面积量算等具体见源代码。

      后台代码实现:

     public MainPageII() //构造函数初始化
     {

        //初始化MyDrawObject,draw工具
        MyDrawObject = new Draw(MyMap)
        {
            FillSymbol = DefaultFillSymbol, //初始化默认的填充颜色
            LineSymbol = DefaultLineSymbol //初始化默认的线颜色
        };

        MyDrawObject.DrawComplete += myDrawObject_DrawComplete; //draw完成触发函数,为了获取框选的范围geometry结果
        MyDrawObject.DrawBegin += myDrawObject_DrawBegin; //draw之前触发函数,设置一些画之前的动作

      }

     private void myDrawObject_DrawBegin(object sender, EventArgs args)
    {
        GraphicsLayer graphicsLayer = MyMap.Layers["MapTipGraphicsLayer"] as GraphicsLayer;//设置GraphicsLayer 
        graphicsLayer.ClearGraphics();//draw之前,清空所有的graphics
    }

   ////////////////////////下面是实现工具栏的功能
    private void myDrawObject_DrawComplete(object sender, DrawEventArgs args)
    {
        if (toolMode == "Rectangle_Query")//toolMode变量来判断是哪种模式框选,此处为矩形,其他框选模式原理是一样的,这里不再写出来
        {
            GraphicsLayer graphicsLayer = MyMap.Layers["MapTipGraphicsLayer"] as GraphicsLayer;
            ESRI.ArcGIS.Client.Geometry.Envelope clickEnvelope = args.Geometry as Envelope;//获取几何范围geometry
            //先判断一下是矢量地图还是遥感地图
            if (rasterMap.IsChecked == true)
            {
                graphicsLayer.ClearGraphics();
            }
            else
            {
                graphicsLayer.ClearGraphics();
                ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic() //定义框选出来的矩形样式颜色
                {
                    Geometry = clickEnvelope,
                    Symbol = DefaultFillSymbol
                };
                graphicsLayer.Graphics.Add(graphic);//添加框选出来的图形显示在地图上
            }
            QueryTask queryTask = new QueryTask("http://192.168.1.4/arcgis/rest/services/SWUMap/MapServer/9");//定义QueryTask
            queryTask.ExecuteCompleted += QueryTask1_ExecuteCompleted; //query查询结果

            queryTask.Failed += QueryTask_Failed;//query查询失败
            Query query = new ESRI.ArcGIS.Client.Tasks.Query(); //定义query对象
            // Specify fields to return from query
            query.OutFields.AddRange(new string[] { "ID", "NAME", "Area", "Length", "X", "Y", "ImagePath" });//设置query条件
            //query.OutFields.Add("*");
            query.Where = "1=1";
            query.Geometry = args.Geometry;//几何条件
            query.ReturnGeometry = true;
            queryTask.ExecuteAsync(query);//执行query查询
            Binding resultFeaturesBinding = new Binding("LastResult");/query查询结果值获取,绑定在datagrid表格用
            resultFeaturesBinding.Source = queryTask;
            Find_QueryDetailsDataGrid.SetBinding(DataGrid.ItemsSourceProperty, resultFeaturesBinding);//获取的查询结果值绑定在datagrid表格
            ShowFindQueryWindow.Begin();
        }
    }

    /// <summary>
    /// 显示选择元素颜色
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    private void QueryTask1_ExecuteCompleted(object sender, ESRI.ArcGIS.Client.Tasks.QueryEventArgs args)
    {
        FeatureSet Query_featureSet = args.FeatureSet;//获取到查询结果集合
        GraphicsLayer graphicsLayer = MyMap.Layers["MapTipGraphicsLayer"] as GraphicsLayer;
        if (Query_featureSet == null || Query_featureSet.Features.Count < 1)
        {
            information.Text = "没有查询记录!";
            ShowImageRoot.Begin();
            return;
        }
        if (Query_featureSet != null && Query_featureSet.Features.Count > 0)
        {
            foreach (Graphic feature in Query_featureSet.Features)
            {
                //先判断一下是矢量地图还是遥感地图
                if (rasterMap.IsChecked == true)
                {
                    feature.Symbol = LayoutRoot.Resources["RemotePicture"] as ESRI.ArcGIS.Client.Symbols.PictureMarkerSymbol;//定义符号颜色样式
                    feature.Geometry = new MapPoint(Convert.ToDouble(feature.Attributes["X"]), Convert.ToDouble(feature.Attributes["Y"]));
                    graphicsLayer.Graphics.Add(feature);
                    RemotePictureStoryboard.Begin();
                }
                else
                {
                    feature.Symbol = LayoutRoot.Resources["ParcelSymbol"] as FillSymbol;//定义符号颜色样式
                    graphicsLayer.Graphics.Insert(0, feature);//查询结果的几何图形显示在地图上
                }
            }
        }
    }

</pre>
** 二、搜索模块,主要包括路径搜索、关键字搜索、范围搜索**



** 1**、关键字搜索,就是普通的query查询,其实应该用locator地理编码服务来实现的,当时自己水平有限,没能使用。把所有兴趣的信息集合在一个图层里面,然后发布地图服务,这样用query查询方式可以达到跟locator一样的目的。
这里贴上核心后台代码好了,前台界面很简单就是一个文本框输入和按钮。

 QueryTask queryTask = new QueryTask("http://192.168.1.4/arcgis/rest/services/SWUMap/MapServer/9");//定义   QueryTask 

queryTask.ExecuteCompleted += QueryTask2_ExecuteCompleted; //query查询结果
Query query = new ESRI.ArcGIS.Client.Tasks.Query(); //定义query对象
query.OutFields.AddRange(new string[] { "ID", "NAME", "Area", "Length", "X", "Y", "ImagePath" });//设置query条件 query.text =****;//文本框获取的文本值
query.ReturnGeometry = true;
queryTask.ExecuteAsync(query);//执行query查询
很类似框选查询的query,不过是设置条件换了,geometry换为text,查询结果一样是在 queryTask.ExecuteCompleted里面获取,获取到关键字查询的结果然后定位到其地理位置显示在地图上。
2、范围搜索,这里用buffer分析方式来实现的,利用buffer获取到几何范围geometry,然后再利用query方式来实现,这里很类似空间查询部分的框选查询,不同的是获取geometry方式不太一样,一个是draw,一个是buffer。
此处是用地图单击事件获取某点,然后利用某点为中心来buffer的,贴上buffer部分代码,后果query代码跟空间查询部分是一样的。
<pre>
GeometryService _geometryService;
** (1)**初始化函数定义
_geometryService = new GeometryService("http://192.168.1.4/arcgis/rest/services/Geometry/GeometryServer");
_geometryService.BufferCompleted += GeometryService_BufferCompleted;
_geometryService.Failed += GeometryService_Failed;

** (2)** 地图单击事件函数
////先判断一下,输入条件是否为空
if (Buffertextbox.Text == "")
{ //MessageBox.Show("请您输入范围搜索条件!");
information.Text = "请您输入范围搜索条件!";
ShowImageRoot.Begin();
return;
}
GraphicsLayer graphicsLayer = MyMap.Layers["MapTipGraphicsLayer"] as GraphicsLayer;
graphicsLayer.ClearGraphics();
_geometryService.CancelAsync();
_queryTask.CancelAsync();
Graphic stop = new Graphic();
if (rasterMap.IsChecked == true) {
stop.Symbol = RemotePicture1;
}
else
{
stop.Symbol = StopSymbol;
}
stop.Geometry = e.MapPoint;//获取地图点坐标
stop.Geometry.SpatialReference = MyMap.SpatialReference;
stop.SetZIndex(2);
graphicsLayer.Graphics.Add(stop);
// Use a projection appropriate for your area of interest
ESRI.ArcGIS.Client.Tasks.BufferParameters bufferParams = new ESRI.ArcGIS.Client.Tasks.BufferParameters() {
//BufferSpatialReference = new SpatialReference(4326),
BufferSpatialReference = new SpatialReference(32648),
OutSpatialReference = MyMap.SpatialReference,
Unit = LinearUnit.Meter//设置地图单位
};
double R = Convert.ToDouble(Buffertextbox.Text);//buffer半径
bufferParams.Distances.Add(R);
bufferParams.Features.Add(stop);
_geometryService.BufferAsync(bufferParams); //执行缓冲分析
</pre>
(3)获取buffer范围结果函数,然后利用geomerey来query查询
<pre>private void GeometryService_BufferCompleted(object sender, GraphicsEventArgs args)
{
Graphic bufferGraphic = new Graphic();
bufferGraphic.Geometry = args.Results[0].Geometry;//获取buffer范围geometry
bufferGraphic.Symbol = BufferSymbol;//定义buffer符号
bufferGraphic.SetZIndex(1);
GraphicsLayer graphicsLayer = MyMap.Layers["GLayer"] as GraphicsLayer;
graphicsLayer.Graphics.Add(bufferGraphic);
ESRI.ArcGIS.Client.Tasks.Query query = new ESRI.ArcGIS.Client.Tasks.Query();
//query.OutFields.Add("*");
query.OutFields.AddRange(new string[] { "DW", "Shape", "ID", "Area", "Length", "NAME","X","Y","ImagePath" });
query.ReturnGeometry = true;
query.Where = "1=1";
query.Geometry = bufferGraphic.Geometry;
_queryTask.ExecuteAsync(query);
Binding resultFeaturesBinding = new Binding("LastResult.Features");
resultFeaturesBinding.Source = _queryTask;
huanchongqujieguo.SetBinding(DataGrid.ItemsSourceProperty,
resultFeaturesBinding);
// BufferResultWindow.IsOpen = true;
//huanchongqujieguo.Visibility = Visibility.Visible;
ShowBufferResultWindow.Begin();
}</pre>
3、路径搜索,最短路径和最优路径,重点详细描述最短路径,最优路径是在最短的路径基础上改造的,这里篇数问题,不再讲。
(1)最短路径,界面是两个文本框和查询按钮,这里不贴了,贴上核心代码:
<pre>//下面是实现路径添加障碍点网络分析
MapPoint MapPointRoute1, MapPointRoute2;
RouteTask _routeTask;
List<Graphic> _stops = new List<Graphic>();
List<Graphic> _barriers = new List<Graphic>();
RouteParameters _routeParams = new RouteParameters(); /////定义Direction
Graphic _activeSegmentGraphic;
DirectionsFeatureSet _directionsFeatureSet;

     /// <summary>        /// 最短路径分析初始化        /// </summary>   
 private void MyShortPathToChoice()        {    
    _routeTask = new RouteTask("http://192.168.1.4/arcgis/rest/services/SWUMap/NAServer/Route");    
    _routeTask.SolveCompleted += routeTask_SolveCompleted;  
      _routeTask.Failed += routeTask_Failed;    
    _routeParams.Stops = _stops;   
    _routeParams.Barriers = _barriers;   
     _routeParams.UseTimeWindows = false;   
     ////定义Direction的            _routeParams.ReturnRoutes = true;/////   
     _routeParams.ReturnDirections = true;   
     _routeParams.DirectionsLengthUnits = esriUnits.esriMiles;
    }
      ///////////////执行路径分析  
   if (_stops.Count > 1)            {  
         // GraphicsLayer stopsLayer = MyMap.Layers["MyStopsGraphicsLayer"] as GraphicsLayer;   
        if (_routeTask.IsBusy)                {    
            _routeTask.CancelAsync();   
             stopsLayer.Graphics.RemoveAt(stopsLayer.Graphics.Count - 1);  
          }     
       _routeTask.SolveAsync(_routeParams);  
      }
    ///////路径分析结果
   private void routeTask_SolveCompleted(object sender, RouteEventArgs e)        {  
      GraphicsLayer routeLayer = MyMap.Layers["MyRouteGraphicsLayer"] as GraphicsLayer;  
      if (e.RouteResults.Count() > 0 && Which_Path1 == "ShortPath")   
     {    
        ////先清空DirectionsStackPanel       
     DirectionsStackPanel.Children.Clear();
            RouteResult routeResult = e.RouteResults[0];                 ////定义Direction 
           _directionsFeatureSet = routeResult.Directions;
            routeResult.Route.Geometry = _directionsFeatureSet.MergedGeometry;
            //routeResult.Route.Symbol = RouteSymbol;     
       routeResult.Route.Symbol = LayoutRoot.Resources["RouteSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol;  
          routeLayer.Graphics.Clear();        
    Graphic lastRoute = routeResult.Route;   
         //decimal totalLength = (decimal)lastRoute.Attributes["Shape_Length"];    
        decimal totalLength = (decimal)lastRoute.Attributes["Total_Length"];   
         string length = string.Format("{0} Meters", totalLength.ToString("#0.000"));    
        Total_Length.Text = length; 
           //decimal totalTime = (decimal)lastRoute.Attributes["Total_Time"];    
        string tip = string.Format("{0} minutes", (totalLength/100).ToString("#0.000"));      
      Total_Time.Text = tip;   
        routeLayer.Graphics.Add(lastRoute); 
           ////Direction       
     int i = 1;    
        foreach (Graphic graphic in _directionsFeatureSet.Features)                {     

           System.Text.StringBuilder text = new System.Text.StringBuilder(); 

               text.AppendFormat("{0}. {1}", i, graphic.Attributes["text"]);   
             if (i > 1 && i < _directionsFeatureSet.Features.Count)                    { 
                   string distance = (Convert.ToDouble(graphic.Attributes["length"])*1609.329).ToString();    
               // string distance = graphic.Attributes["length"].ToString();       
            // string distance = graphic.Attributes["length"].ToString();     
               string time = null;       
             if (graphic.Attributes.ContainsKey("time"))                        {     
                   //time = FormatTime(Convert.ToDouble(graphic.Attributes["time"]));     
                   time = graphic.Attributes["time"].ToString();     
               }        
            if (!string.IsNullOrEmpty(distance) || !string.IsNullOrEmpty(time))    
                    text.Append(" (");      
              text.Append(distance);
                    if (!string.IsNullOrEmpty(distance) && !string.IsNullOrEmpty(time))    
                    text.Append(", ");      
              text.Append(time);   
                 if (!string.IsNullOrEmpty(distance) || !string.IsNullOrEmpty(time))    
                    text.Append(")");  
              }         
       TextBlock textBlock = new TextBlock() { Text = text.ToString(), Tag = graphic, Margin = new Thickness(4), Cursor = Cursors.Hand }; 
               textBlock.MouseLeftButtonDown += new MouseButtonEventHandler(directionsSegment_MouseLeftButtonDown);  
              DirectionsStackPanel.Children.Add(textBlock);    
            i++;        
    }                

MyMap.ZoomTo(Expand(_directionsFeatureSet.Extent));
}
}
private void directionsSegment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
TextBlock textBlock = sender as TextBlock;
Graphic feature = textBlock.Tag as Graphic;
MyMap.ZoomTo(Expand(feature.Geometry.Extent));
if (_activeSegmentGraphic == null) {
_activeSegmentGraphic = new Graphic()
{
Symbol = LayoutRoot.Resources["SegmentSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol
};
GraphicsLayer graphicsLayer = MyMap.Layers["MyRouteGraphicsLayer"] as GraphicsLayer;
graphicsLayer.Graphics.Add(_activeSegmentGraphic);
}
_activeSegmentGraphic.Geometry = feature.Geometry;
}
private void stackPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (_directionsFeatureSet != null) {
GraphicsLayer graphicsLayer = MyMap.Layers["MyRouteGraphicsLayer"] as GraphicsLayer;
MyMap.ZoomTo(Expand(_directionsFeatureSet.Extent));1n
}
}
private Envelope Expand(Envelope e) {
double factor = 0.6;
MapPoint centerMapPoint = e.GetCenter();
return new Envelope(centerMapPoint.X - e.Width * factor, centerMapPoint.Y - e.Height * factor, centerMapPoint.X + e.Width * factor, centerMapPoint.Y + e.Height * factor);
} </pre>
** 三**、GPS模拟定位,这里说说思路好了,具体见源代码。主要是模拟校车每个时刻的地位Point,然后再描绘出来连接成线line,最后添加再地图上显示出来。应用到arcgis api的对象point、line、graphic、geometry、graphiclayer等等。
、统计分析,这里不描述了,具体见源代码。

GIS之家新博客系列发布更新在GIS之家网站,欢迎关注收藏:GIS之家网站
GIS之家作品:GIS之家
GIS之家交流咨询:咨询模式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容