设施网络分析 |
使用场景说明1:现有某区域的河流网络图,在该河流网络的下游某一监测点测得河流污染物超标,现在需要知道该检测点上游的哪些河道可能存在污染源。
使用场景说明2 :在上游河流旁边的某一个位置有一个化工厂,由于排污不达标造成对下游的污染,需要知道被污染河道的范围及数量。
使用场景说明3:在经过分析和判断之后发现可疑污染源的位置,现在需要寻找一个与可疑的污染源点水路相连的监测点,以方便监测船沿路监测污染物含量。
使用已经制作完成的 SampleData 数据——FacilityAnalyst。FacilityAnalyst 数据位于 SuperMap iObjects .NET安装目录 SampleData 目录下,FacilityAnalyst 的工作空间文件——FacilityAnalyst.smw,所用的数据为 FacilityAnalyst.udb,引擎类型为UDB,所含主要图层包括 WaterNet(河流网络数据集)、Water_L(河道线数据集)等多个图层。本示范程序就是针对该示范数据中的已经建立好流向的网络数据集进行分析处理,主要涉及上游追踪、下游追踪、连通性分析等。
假设已经加载了一个工作空间 m_workspace 和地图控件 m_mapControl,并且已经将两者关联。在窗体中添加相应的功能按钮:
表 9.1 控件属性设置说明
Name |
Text |
toolStripButton_LoadModel |
加载模型 |
toolStripButton_SelectElement |
选取要素 |
toolStripButton_TraceUp |
上游追踪 |
toolStripButton_TraceDown |
下游追踪 |
toolStripButton_Connected |
连通性分析 |
toolStripButton_Clear |
清空 |
在正式编写示范程序之前,需要添加对 SuperMap 组件产品的 Mapping、UI、Data 和 Networkanalyst 程序集的引用,进入代码编辑器,在最顶端添加如下代码:
using SuperMap.Data; using SuperMap.Mapping; using SuperMap.UI; using SuperMap.Analyst.NetworkAnalyst; |
在主窗体的 Load 事件中添加打开指定的工作空间及数据集,并将指定数据集显示在地图控件中。默认数据源 m_datasource、数据集 m_netLine、图层 m_netLineLayer 需要提前定义。在打开文件时使用的是相对路径,也可以使用绝对路径。
// 打开指定的工作空间,并加载指定的地图和数据集 private void FormMain_Load(object sender, EventArgs e) { // 打开指定的工作空间 WorkspaceConnectionInfo conInfo = new WorkspaceConnectionInfo(@"..\..\SampleData\FacilityAnalyst\FacilityAnalyst.smwu"); m_workspace.Open(conInfo); //建立MapControl与Workspace的连接 m_mapControl.Map.Workspace = m_workspace; //获取工作空间中指定数据源中的数据集 m_datasource = m_workspace.Datasources[0]; m_netLine = m_datasource.Datasets["WaterNet"] as DatasetVector; //在地图控件中打开指定的地图对象 m_mapControl.Map.Open("WaterNet"); m_netLineLayer = m_mapControl.Map.Layers[1]; //设定地图显示范围 m_mapControl.Map.EnsureVisible(m_netLineLayer, 4); //初始化图层选择状态 m_mapControl.Map.Layers[2].IsSelectable = false; m_mapControl.Map.Layers[3].IsSelectable = false; //刷新地图 m_mapControl.Map.Refresh(); } |
程序运行结束后,应当释放该程序所占用的内存资源,本例结束运行时需释放 MapControl 控件和 Workspace 对象所占用的资源,并且,释放的顺序先释放 MapControl 控件,后释放 Workspace 对象占用的资源。
1. 选择“视图”>“设计器”来显示设计视图。在设计视图中,请选定 FormMain 窗体。
2. 在“属性”窗口中,单击“事件”按钮。
3. 选择 FormClosing 事件。
4. 在文本框中输入 FormMain_FormClosing,然后按回车键。随后会创建一个名为 FormMain _FormClosing 的事件方法,并在“代码和文本编辑器”窗口中显示,添加如下代码。
// 释放的顺序推荐先释放MapControl控件,后释放Workspace对象 private void FormMain_FormClosing (object sender, FormClosingEventArgs e) { m_mapControl.Dispose(); m_workspace.Dispose(); } |
在前面的介绍中已经知道,设施网络分析需要对分析环境进行设置,并且在设置完分析环境之后需要调用 FacilityAnalyst 类的 Load 方法加载设施网络分析数据,只有调用了 FacilityAnalyst 类的 Load 方法,所设置的设施网络分析环境才会生效,才能利用 FacilityAnalyst 类中的各种方法进行设施网络分析。在“加载模型”Click 事件中添加如下代码:
// 加载设施网络模型 private void toolStripButton_LoadModel_Click(object sender, EventArgs e) { try { //定义设施网络分析环境设置参数 FacilityAnalystSetting analystSetting = new FacilityAnalystSetting(); analystSetting.NetworkDataset = m_netLine; analystSetting.NodeIDField = "SmNodeID"; analystSetting.EdgeIDField = "SmID"; analystSetting.FNodeIDField = "SmFNode"; analystSetting.TNodeIDField = "SmTNode"; analystSetting.DirectionField = "Direction"; analystSetting.Tolerance = 5; //定义权值字段信息 WeightFieldInfo info = new WeightFieldInfo(); info.Name = "length"; info.FTWeightField = "SmLength"; info.TFWeightField = "SmLength"; WeightFieldInfos infos = new WeightFieldInfos(); infos.Add(info); analystSetting.WeightFieldInfos = infos; //定义设施网络分析 m_facilityAnalyst = new FacilityAnalyst(); m_facilityAnalyst.AnalystSetting = analystSetting; //加载用于设施网络分析的数据信息 m_facilityAnalyst.Load(); //设置是否启用按钮 toolStripButton_SelectElement.Enabled = true; toolStripButton_LoadModel.Enabled = false; } catch(Exception ex) { Trace.WriteLine(ex.Message); } } |
加载模型之后,需要选择要素点进行分析,在添加“选择要素”按钮的 Click 事件代码之前,需要在窗体的构造函数中添加如下代码,用于设置捕捉的方式以及注册地图控件鼠标移动和鼠标点击事件,其中 m_hasSnapped 和 m_elementIDs 需要提前定义:
public FormMain() { InitializeComponent(); //设置捕捉设置的参数 m_mapControl.SnapSetting.MaxSnappedCount = 3000; m_mapControl.SnapSetting[SnapMode.PointOnPoint] = true; m_mapControl.SnapSetting[SnapMode.PointWithHorizontalOrVertical] = false; m_mapControl.SnapSetting[SnapMode.PointOnEndpoint] = false; m_mapControl.SnapSetting[SnapMode.PointOnExtension] = false; m_mapControl.SnapSetting[SnapMode.PointOnLine] = false; m_mapControl.SnapSetting[SnapMode.PointOnMidpoint] = false; m_mapControl.IsWaitCursorEnabled = false; //初始化m_hasSnapped值,控制是否选中要素 m_hasSnapped = false; //初始化m_elementIDs值,存储要素几何对象的ID m_elementIDs = new List<Int32>(); //注册地图控件鼠标移动和鼠标点击事件 m_mapControl.MouseMove += new MouseEventHandler(m_mapControl_MouseMove); m_mapControl.MouseClick += new MouseEventHandler(m_mapControl_MouseClick); } |
// “选择要素”按钮点击事件 private void toolStripButton_SelectElement_Click(object sender, EventArgs e) { try { //设置是否启用按钮功能 toolStripButton_TraceDown.Enabled = true; toolStripButton_TraceUp.Enabled = true; toolStripButton_Connected.Enabled = true; toolStripButton_Clear.Enabled = true; //设置图层是否可编辑及定义地图控件的操作状态 m_mapControl.Map.Layers[0].IsEditable = true; m_mapControl.Action = SuperMap.UI.Action.PickSnapPoint; //刷新地图 m_mapControl.Map.Refresh(); } catch(Exception ex) { Trace.WriteLine(ex.Message); } } |
点击“选择要素”按钮之后,在地图控件中移动鼠标选择要素点,因此需要设置捕捉方便对点的选择,在地图控件的 MouseMove 事件中添加如下代码,其中 m_hasSnapped 是定义的一个 Boolean 型的全局变量:
// 地图控件鼠标移动事件 Public void m_mapControl_MouseMove(object sender, MouseEventArgs e) { try { //获得地图控件的被捕捉的元素 SnappedElement[] elements = m_mapControl.GetSnappedElements(); if (elements.Length > 0) { m_hasSnapped = true; Double scale = m_mapControl.Map.Scale; //定义几何风格 GeoStyle style = new GeoStyle(); style.LineColor = Color.FromArgb(255, 255, 102, 255); style.LineWidth = 0.15; /定义二维矩形几何对象 GeoRectangle rect = new GeoRectangle(elements[0].SnappedPoints[0], 0.005/scale, 0.005/scale, 0); GeoLine geoLine = rect.ConvertToLine(); geoLine.Style = style; //判断地图控件中是否已有捕捉矩形框,如果有,则移出 Int32 index = m_mapControl.Map.TrackingLayer.IndexOf(m_lineTag); if (index > 0) { m_mapControl.Map.TrackingLayer.Remove(index); } //在跟踪图层中添加捕捉矩形框 m_mapControl.Map.TrackingLayer.IsVisible = true; m_mapControl.Map.TrackingLayer.Add(geoLine, m_lineTag); //刷新跟踪图层 m_mapControl.Map.RefreshTrackingLayer(); } } catch(Exception ex) { Trace.WriteLine(ex.Message); } } |
在完成对点的选择之后,需要通过鼠标点击选择要素点,因此需要在地图控件的 MouseClick 事件中添加如下代码,其中 m_elementIDs 是定义好的一个 List<Int32> 全局变量,用于存储要素点的 ID 号:
// 地图控件鼠标点击事件 Public void m_mapControl_MouseClick(object sender, MouseEventArgs e) { try { if(m_hasSnapped) { //获得地图控件的被捕捉的元素 SnappedElement[] elements = m_mapControl.GetSnappedElements(); m_elementIDs.Add(elements[0].GeometryID); GeoPoint point = new GeoPoint(elements[0].SnappedPoints[0]); //设置点元素的显示风格 GeoStyle style = new GeoStyle(); style.MarkerSize = new Size2D(10, 10); style.LineColor = Color.Red; style.MarkerSymbolID = 3614; point.Style = style; //定义显示文本 Int32 count = m_elementIDs.Count; TextPart textPart = new TextPart("要素" + count, elements[0].SnappedPoints[0]); GeoText geoText = new GeoText(textPart); //设置文本显示风格 TextStyle textStyle = new TextStyle(); textStyle.ForeColor = Color.Green; geoText.TextStyle = textStyle; //跟踪图层中添加几何对象及文本 m_mapControl.Map.TrackingLayer.Add(point, ""); m_mapControl.Map.TrackingLayer.Add(geoText, ""); //刷新跟踪图层 m_mapControl.Map.Refresh(); } } catch (Exception ex) { Trace.WriteLine(ex.Message); } } |
选择完要素点之后,联想到案例开始时候的使用场景1,选择完检测到受污染的点之后,需要分析得出有可能的污染源所在的河道。首先需要添加分析完之后的更换鼠标状态的方法 ChangeAction的代码,该方法中具有一个Action参数。
// 更换鼠标状态 public void ChangeAction(Action value) { try { if(value == Action.Pan) { m_mapControl.Map.Layers[0].IsEditable = false; } m_mapControl.Action = value; m_mapControl.Map.Refresh(); } catch(Exception ex) { Trace.WriteLine(ex.Message); } } |
在设置好鼠标更换方法之后,需要在“上游追踪”按钮中添加相应代码,以实现对疑似污染源的查找,需要提前定义一个 Boolean 型的全局变量 m_hasAnalysted。
// “上游追踪”按钮点击事件 private void toolStripButton_TraceUp_Click(object sender, EventArgs e) { try { //设置是否开启按钮功能 toolStripButton_SelectElement.Enabled = false; toolStripButton_TraceDown.Enabled = false; toolStripButton_Connected.Enabled = false; toolStripButton_TraceUp.Enabled = false; //修改是否已有分析值 m_hasAnalysted = true; //根据m_elementIDs存储的点分别进行分析 if(m_elementIDs.Count > 0) { m_mapControl.Map.Layers[0].Selection.Clear(); //设置结果几何对象风格 GeoStyle style = new GeoStyle(); style.LineColor = Color.FromArgb(255, 204, 150, 0); style.LineWidth = 0.2; style.LineSymbolID = 41;
for (Int32 i = 0; i < m_elementIDs.Count; i++) { //获取分析结果几何对象的ID集 FacilityAnalystResult result = m_facilityAnalyst.TraceUpFromNode(m_elementIDs[i], "length", true);
m_mapControl.Map.Layers[1].Selection.AddRange(result.Edges); m_mapControl.Map.Layers[1].Selection.Style = style; } //刷新地图 m_mapControl.Map.Refresh(); //改变操作状态 ChangeAction(Action.Pan); } } catch(Exception ex) { Trace.WriteLine(ex.Message); } } |
分析结果见图 9‑1:
|
图 9‑1 上游追踪分析 |
结合使用场景2,在选择完污染源之后,需要分析查找出受污染的河道,在“下游追踪”按钮的点击事件中添加如下代码:
// “下游追踪”按钮点击事件 public void toolStripButton_TraceDown_Click(object sender, EventArgs e) { try { //设置是否开启按钮功能 toolStripButton_SelectElement.Enabled = false; toolStripButton_TraceDown.Enabled = false; toolStripButton_Connected.Enabled = false; toolStripButton_TraceUp.Enabled = false; //修改是否已有分析值 m_hasAnalysted = true; //根据m_elementIDs存储的点分别进行分析 if (m_elementIDs.Count > 0) { m_mapControl.Map.Layers[0].Selection.Clear(); /设置结果几何对象风格 GeoStyle style = new GeoStyle(); style.LineColor = Color.FromArgb(255, 204, 150, 0); style.LineWidth = 0.2; style.LineSymbolID = 41;
for (Int32 i = 0; i < m_elementIDs.Count; i++) { //获取分析结果几何对象的ID集 FacilityAnalystResult result = m_facilityAnalyst.TraceDownFromNode(m_elementIDs[i], "length", true);
m_mapControl.Map.Layers[1].Selection.AddRange(result.Edges); m_mapControl.Map.Layers[1].Selection.Style = style; } //刷新地图 m_mapControl.Map.Refresh(); //改变操作状态 ChangeAction(Action.Pan); } } catch (Exception ex) { Trace.WriteLine(ex.Message); } } |
分析结果见图 9‑2:
|
图 9‑2 下游追踪分析 |
结合使用场景3,需要判断两个要素点之间是否连通,以确保可以派出检测船沿途检测污染物含量,需要在“连通性分析”按钮的点击事件中添加如下代码:
// “连通性分析”按钮点击事件 private void toolStripButton_Connected_Click(object sender, EventArgs e) { try { //设置是否开启按钮功能 toolStripButton_SelectElement.Enabled = false; toolStripButton_TraceDown.Enabled = false; toolStripButton_Connected.Enabled = false; toolStripButton_TraceUp.Enabled = false; //修改是否已有分析值 m_hasAnalysted = true; //根据m_elementIDs存储的点分别进行分析 if (m_elementIDs.Count > 0) { List<Int32> resultArcIDs = new List<Int32>(); Int32[] ids = m_elementIDs.ToArray(); for (Int32 i = 0; i < ids.Length-1; i++) { //获取分析结果几何对象 FacilityAnalystResult result = m_facilityAnalyst.FindPathFromNodes(ids[i], ids[i+1], "length"); resultArcIDs.AddRange(result.Edges); } //设置结果几何对象风格 GeoStyle style = new GeoStyle(); style.LineColor = Color.FromArgb(255, 204, 150, 0); style.LineWidth = 0.2; //清空图层选择集,并把分析结果元素加入到选择集中 m_mapControl.Map.Layers[1].Selection.Clear(); m_mapControl.Map.Layers[1].Selection.AddRange(resultArcIDs.ToArray()); m_mapControl.Map.Layers[1].Selection.Style = style; //刷新地图 m_mapControl.Map.Refresh(); //改变操作状态 ChangeAction(Action.Pan); } } catch (Exception ex) { Trace.WriteLine(ex.Message); } } |
分析结果见图 9‑3:
|
图 9‑3 连通性分析 |
在做完一次分析之后,地图窗口中会显示分析的结果,在进行另外一个功能分析前,需要清空各种图层要素。
// “清空”按钮点击事件 private void toolStripButton_Connected_Click(object sender, EventArgs e) { try { //清空图层、跟踪图层 m_mapControl.Map.Layers[0].Selection.Clear(); m_mapControl.Map.Layers[1].Selection.Clear(); m_mapControl.Map.TrackingLayer.Clear(); m_elementIDs.Clear(); //刷新地图 m_mapControl.Map.Refresh(); } catch (Exception ex) { Trace.WriteLine(ex.Message); } } |