一、MapX简介
MapX控件是由MapInfo公司提供的具有强大地图分析功能的ActiveX控件产品。由于它是一种基于Windows操作系统的标准控件,因而能支持大多数标准的可视化开发环境,如Visual Basic、Visual C++、Delphi和PowerBuilder等。通过MapX控件可以将地图功能嵌入到应用程序中,并可脱离MapInfo的软件平台运行。MapX控件按图层组织地图,每个图层包含整个地图的一个方面并对应一个MapInfo表。文中的中国主干公路网由“中国主干公路节点”图层和“中国主干公路线”图层组成,数据为MapInfo格式。中国主干公路节点.tab和中国主干公路线.tab数据组织格式如图1和图2所示。
图1 中国主干公路节点.tab
图2 中国主干公路线.tab
二、Dijkstra算法
Dijkstra算法是目前公认的效率较高的最短路径算法。算法基本思想是采用标号的方法,从起点开始逐步向外搜索起点到其他各点的最短路径。算法基本步骤如下:
首先给起始节点标上永久性标号0,然后给每个与起始节点直接相连的节点标上一个临时标号,标号值为连接起始节点和该节点线路的长度值。给其他未与起始节点直接相连的节点的临时标号为 。
选择具有最小临时标号的节点,将该节点的临时标号改为永久性标号。假设节点 是刚获得永久性标号的节点,搜索每个与节点 直接相连且具有临时标号的节点 ,用min{节点 目前的临时标号,节点 的永久性标号+线路 的长度值}对节点 的临时标号进行更新。
重复以上步骤,直到所有节点都具有永久性标号。此时的每个永久性标号值,代表起始节点到该节点的最短距离。如果只要求起点到指定终点的最短距离,则在指定终点获得永久性标号时即可停止标号过程。
要求出起点到终点的最短路径,需要从终点逆推,求出永久标号差值正好等于线路长度的节点以下为算法示例。
在图3中,查询从节点1到节点6的最短路径的标号过程如下:(*表示永久性标号)
图3 算法示例
所以节点1到节点6的最短距离为8,进行逆推求最短路径。节点6和节点5之间的永久标号之差是8-6=线路(5,6)的长度,所以可以回到节点5。节点5和节点2之间的永久标号之差是6-4=线路(2,5)的长度,回到节点2。节点2和节点1的永久标号之差4=线路(1,2)的长度,回到起点1,得到最短路径1-2-5-6。在节点5时,还可以回到节点3得到最短路径1-3-5-6。
三、程序实现
在VB中引用MapX控件的步骤为:工程→部件→控件→MapInfo MapX V5。在窗口中加入MapX控件,添加菜单、工具栏、文本框等,程序界面如图4所示。在MapX控件中添加“中国主干公路节点”和“中国主干公路线”图层步骤为:在MapX控件上点右键→特性→Layers→Add,选中要添加的图层即可,实现的核心代码如下:
图4 程序界面
Option Base 1
Const select_point As Integer = 1
Dim nodelayerindex As Integer, linelayerindex As Integer
Dim LatNode() As Double, LonNode() As
Double, NoNode() As Integer, nNode As
Integer '节点的纬度、经度、标注、节点数
Dim LineNode() As Integer, LineDis() As
Double, nLineNode As Integer
'线路的端点(redim成二维的)、长度、
'线路数
Dim StartNo As Integer, EndNo As Integer '查询时指定的起点、终点
Dim flagMatrix() As Boolean, distmatrix() As
Double '标记节点是否邻接、邻接距离
Dim yjdb() As Boolean, distvector() As
Double
'标记节点是否获得永久标号、与起点的距离
Dim tempstartno As Integer, tempendno As
Integer, oldtempstartno As Integer
Dim isall As Boolean
'标记是否所有节点都获得永久标号
Dim szdno() As Integer '最短路径上的节点
Dim shortestdist As Double '最短距离
Private Sub Form_Load() '初始化,读取数据
Map1.CreateCustomTool select_point,
miToolTypePoint, miCenterCursor
'创建用户自定义点选择工具,
'用于指定起点、终点
Dim lyr As MapXLib.Layer
Dim nodelyr As MapXLib.Layer, nodeds As
MapXLib.Dataset
Dim ftr As MapXLib.Feature
Dim i As Integer, j As Integer, k As Integer,
temp As Integer, q As Integer, maxlen As
Double
For Each lyr In Map1.Layers '添加数据集
Map1.DataSets.Add miDataSetLayer, lyr,
lyr.Name & "dataset"
Next
For i = 1 To Map1.Layers.Count
If Map1.Layers(i).Name = "中国主干公路节点" Then
nodelayerindex = i '公路节点图层编号
End If
If Map1.Layers(i).Name = "中国主干公路线" Then
linelayerindex = i '线路图层编号
End If
Next i
Set nodelyr = Map1.Layers(nodelayerindex)
nodelyr.AutoLabel = True
Set nodeds = Map1.DataSets.
Add(miDataSetLayer, nodelyr)
Set nodelyr.LabelProperties.Dataset = nodeds
Set nodelyr.LabelProperties.DataField =
nodeds.Fields(3)
nodelyr.LabelProperties.Position =
miPositionCR
nodelyr.LabelProperties.Visible = True
nNode = 0: nLineNode = 0
For Each ftr In
Map1.Layers(nodelayerindex).AllFeatures
nNode = nNode + 1 '节点数
Next
For Each ftr In
Map1.Layers(linelayerindex).AllFeatures
nLineNode = nLineNode + 1 '线路数
Next
ReDim LonNode(1 To nNode) As Double,
LatNode(1 To nNode) As Double, NoNode(1
To nNode) As Integer '节点初始化
ReDim LineNode(1 To 2, 1 To nLineNode),
LineDis(1 To nLineNode) '线路初始化
For i = 1 To nNode
LatNode(i) =
Map1.DataSets(nodelayerindex).Value(i, 1)
'公路节点的纬度
LonNode(i) =
Map1.DataSets(nodelayerindex).Value(i, 2)
'经度
NoNode(i) =
Map1.DataSets(nodelayerindex).Value(i, 3)
'标注
Next i
For i = 1 To nLineNode
LineNode(1, i) =
Map1.DataSets(linelayerindex).Value(i, 1)
'线路的第1个节点
LineNode(2, i) =
Map1.DataSets(linelayerindex).Value(i, 2)
'线路的第2个节点
LineDis(i) =
Map1.DataSets(linelayerindex).Value(i, 3)
'线路长度
Next i
ReDim flagMatrix(1 To nNode, 1 To nNode)
As Boolean
ReDim distmatrix(1 To nNode, 1 To nNode)
As Double
For i = 1 To nNode
'flagMatrix标记节点是否邻接
For j = 1 To nNode '初始化
|