一个地图编辑工具


本节内容可以参考CaseStudy目录下的文件"地图.Table"的示例三十五。

提示: 普通用户不用研究本示例的代码,将其当做一个强大的地图编辑工具直接使用即可。


如果你想在离线地图上绘制某未知名的河流或道路的走向,或某个乡镇(或村)的大概范围,或临时决定勾画某区域(例如受灾范围),那么如何获得目标的经纬度数据呢?

有些目标的经纬度数据,是可以通过第三方服务获取的,但有些事没有办法的。

此时你可以打开本节的示例(建议实际使用的时候,地图源采用高德地图),然后找到目标,例如某条河流,然后沿着河流走向绘制一条线,即可得到该河流的经纬度数据。

你需要更高精度的数据时,放大地图进行绘制,需要更粗略的数据时,缩小地图进行绘制。

这个工具可以将编辑结果保存在数据表中(类似示例文件中的行政区域表), 大家可以在这个工具的基础上进行扩展,例如加上颜色和宽度的选择以及标题的设置。

这是示例的代码量有500行,是Foxtable代码量最大的一个示例,而且不同的事件代码之间环环相扣,如果你理解起来有困难,是再正常不过了,真的没必要去死扣,直接套用就行了。

如前所言,本示例是一个很重要的工具,原本是要直接内置在Map控件中的,但这样的话用户扩展不方便,同时我们也想给高端用户提供一个开发复杂功能的示例,于是将这部分代码提炼出来做成了一个Foxtable项目。

如果你能理解消化好这个例子,对于你今后的开发肯定是有益的,但千万不要勉强。

本节的任务模仿阿里云的在线地图编辑器:

https://datav.aliyun.com/portal/school/atlas/area_generator

用Foxtable开发一个可以在地图上任意编辑涂鸦的工具:

1、可以插入 标记、线条、四边形、多边形和圆形

2、可以随意移动形状

3、可以随意调整现有形状

4、可以随意旋转现有形状

5、对于线条和多边形,可以在任意位置插入或删除顶点:

下面是本示例的完整代码,代码有详尽的注释,请自行研究理解消化:

1、窗口AfterLoad事件代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As New VectorLayer()
map.Layers.Add(layer)
layer.Style.Stroke.Color = Color.LightGray
layer.LabelVisibility = LabelVisibility.Visible
map.Viewport.Margin = New Padding(0, 32, 0, 0) '地图上方留空32个像素用于放置按钮
'提前准备全局变量
Vars("CurrentButton") = "btnSelect" '用Var变量记录当前按钮
e.Form.Controls("btnSelect").Theme = "GreenHouse" ' 当前按钮用不同的样式标记
Vars("GeoPointsClicked") = New List(Of GeoPoint) '一个集合,用于收集绘制形状过程中,用户点击鼠标确认的位置点
Vars.Add("DataRowToDraw", GetType(DataRow), Nothing) '调用绘制按钮绘制形状时,要先将数据行存储在这个Var变量中
Vars.Add("VectorItemDrawn", GetType(VectorItem), Nothing) '用绘制按钮绘制完成的形状,将存储在这个Var变量中,方便调用者使用
Vars.Add("TempVectorItem", GetType(VectorItem), Nothing) '用于存储在涂鸦过程中生成的临时形状
Vars.Add("VectorItemSelected", GetType(VectorItem), Nothing) '用于存储当前选中的形状
Vars.Add("TipMark", GetType(VectorPlacemark), Nothing) '用于存储一个标记,这个标记会在用户绘制形状的过程中,给用户一些动态提示
Vars.Add("StartPoint", GetType(GeoPoint), Nothing) '在拖动或调整形状时,用于记录鼠标的初始位置
Vars("AdjustState") = True '是否处于调整状态
Vars("AdjustMarks") = New List(Of VectorPlacemark) '一个集合,用于收集调整状态下生成的调整标记
Vars.Add("AdjustMark", GetType(VectorItem), Nothing) '用于记录正在拖动的调整标记
'创建用于提示的TipMark标记
Dim mark As New VectorPlacemark
mark.Marker.Size = New SizeF(6, 6)
mark.Marker.Shape = MarkerShape.Circle
mark.Style.BackColor = Color.Blue
mark.Style.Stroke.Color = Color.Blue
mark.LabelStyle.ForeColor = Color.RosyBrown
mark.Marker.LabelPosition = LabelPosition.Top
mark.Visible = False
layer.Items.Add(mark)
Vars("TipMark") = mark
'绘制省级行政区作为背景,如果需要高精度的绘制,可以用高德地图作为背景
For Each dr As DataRow In DataTables("行政区域").Select("level= 1")
    layer.Items.Add(map.CreatePolygon(dr("geometry")))
Next
'绘制用户之前涂鸦好的形状
For Each dr As DataRow In DataTables("涂鸦").DataRows
    Vars("DataRowToDraw") = dr
    e.Form.Controls("btnDrawItem").PerformClick()
Next

2、窗口全局Click事件代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
map.Focus()
Dim layer As VectorLayer = map.Layers(0)
Select Case e.Sender.Name
    Case "btnSelect", "btnMark", "btnLine", "btnPolygon", "btnCircle", "btnRectangle"
        e.Form.Controls("btnUnSelect").PerformClick() '取消之前选择的形状
        e.Form.Controls(Vars("CurrentButton")).Theme = "(default)" '前一个当前按钮恢复默认样式
        Vars("CurrentButton") = e.Sender.Name '将单击的按钮设置为当前按钮
        e.Sender.Theme = "GreenHouse" '改变当前按钮的样式
        Vars("GeoPointsClicked").Clear() '清除绘制中添加的临时位置点,如果有的话
        Vars("VectorItemDrawn") = Nothing '从Var变量中清除刚刚绘制的形状,如果有的话
        If Vars("TempVectorItem") IsNot Nothing Then '移除临时绘制的形状,如果有的话
            layer.Items.Remove(Vars("TempVectorItem"))
            Vars("TempVectorItem") = Nothing
        End If
        Dim tipMark As VectorPlacemark = Vars("TipMark")
         tipMark.Visible = (e.Sender.Name <> "btnSelect") '如果当前按钮是"选择",则隐藏提示标记
        Select Case e.Sender.Name '不同的当前按钮,显示不同的提示内容
            Case "btnMark"
                tipMark.Marker.Caption = "单击放置标记"
            Case "btnLine", "btnRectangle", "btnPolygon"
                tipMark.Marker.Caption = "单击放置首点"
            Case "btnCircle"
                tipMark.Marker.Caption = "单击放置圆心"
        End Select
End Select

3、"可调"按钮代码:

Vars("AdjustState") = Not Vars("AdjustState") '切换可调状态
If Vars("AdjustState") Then '如果是可调状态
    e.Sender.Theme = "GreenHouse" '改变按钮样式
Else
    e.Sender.Theme = "(default)" '否则恢复默认样式
End If
If Vars("CurrentButton") <> "btnSelect" Then '如果当前按钮不是"选择"
    e.Form.Controls("btnSelect").PerformClick() '则模拟单击选择按钮
End If
e.Form.Controls("btnDrawAdjustMarks").PerformClick() '绘制(或清除)调整标记

4、"旋转"按钮代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
If Vars("VectorItemSelected") IsNot Nothing Then
    Dim ItemSelected As VectorItem = Vars("VectorItemSelected") '获取选择的形状  
    Dim dr As DataRow = ItemSelected.Tag '获取形状对应的数据行
    If dr("类型") = "Mark" OrElse dr("类型") = "Circle" Then '标记和旋转没有必要旋转
        Return
    ElseIf dr("类型") = "Rectangle" Then '平行四边形其实也没有旋转的必要,如果要旋转,要先转换为普通多边形才行
        Dim ps() As String = dr("数据").Split(",")
        dr("类型") = "Polygon"
        dr("数据") = ps(0) & "," & ps(1) & "," & ps(0) & "," & ps(3) & "," & ps(2) & "," & ps(3) & "," & ps(2) & "," & ps(1)
    End If
    Dim angle As Integer = 30 '默认顺时钟旋转30度
    If ModifierKey = Keys.Shift Then '如果按住了Shift键
        angle = -30 '则逆时钟旋转30度
    End If
    dr("数据") = map.RolateGeoPointString(dr("数据"), angle) '直接针对数据进行旋转计算
    Vars("DataRowToDraw") = dr '然后根据新数据绘制形状
    e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮生成并绘制一个新形状
    Dim itemNew As VectorItem = Vars("VectorItemDrawn") '获得刚刚生成的新形状
    itemNew.Style.Stroke.Color = ItemSelected.style.Stroke.Color '新形状和原形状的边框被背景颜色一致
    itemNew.Style.BackColor = ItemSelected.Style.BackColor
    layer.Items.Remove(ItemSelected) '移除原形状
    Vars("VectorItemSelected") = itemNew '将新形状设置为选中
    e.Form.Controls("btnDrawAdjustMarks").PerformClick() '绘制调整标记    
End If
e.Cancel = True '没必要执行窗口的全局Click事件了

5、"删除"按钮代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
If Vars("VectorItemSelected") IsNot Nothing Then
    Dim ItemSelected As VectorItem = Vars("VectorItemSelected") '获取选择的形状  
    Dim dr As DataRow = ItemSelected.Tag '获取形状对应的数据行
    dr.Delete() '删除数据行
    e.Form.Controls("btnUnSelect").PerformClick() '模拟取消选择
    layer.Items.Remove(ItemSelected) '移除形状
    Vars("VectorItemSelected") = Nothing
    Vars("StartPoint") = Nothing
End If
e.Form.Controls("btnSelect").PerformClick() '模拟单击选择按钮
e.Cancel = True '已经没必要执行窗口的全局Click事件了

6、Map控件的MouseClick事件代码:

Dim map As GeoMap = e.Sender.GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim curPoint As GeoPoint = map.MouseGeoPosition '获取鼠标位置
Dim tipMark As VectorPlacemark = Vars("TipMark") '获取提示标记
Dim gps As List(Of GeoPoint) = Vars("GeoPointsClicked") '获取之前单击确认的位置点
Select Case vars("CurrentButton") '根据当前按钮判断要绘制的形状类型
    Case "btnMark" '绘制标记
        Dim dr As DataRow = DataTables("涂鸦").AddNew
        dr("类型") = "Mark"
        dr("数据") = curPoint.X & "," & curPoint.y
        dr.Save()
        Vars("DataRowToDraw") = dr '将数据行存在Var变量中,方便绘制按钮调用
        e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮绘制标记
    Case "btnLine", "btnPolygon" '对于线条或多边形,单击只是添加位置点,完成绘制需要双击
        gps.Add(curPoint)
        If vars("CurrentButton") = "btnLine" OrElse gps.Count >= 2 Then
            tipMark.Marker.Caption = "单击继续,双击结束"
        Else
            tipMark.Marker.Caption = "单击继续"
        End If
    Case "btnRectangle" '绘制四边形
        If gps.Count = 0 Then
            gps.Add(curPoint)
            tipMark.Marker.Caption = "单击确定对角点"
        Else
            Dim p1 As GeoPoint = gps(0)
            Dim p2 As GeoPoint = curPoint
            Dim dr As DataRow = DataTables("涂鸦").AddNew()
            dr("类型") = "Rectangle"
            dr("数据") = p1.X & "," & p1.Y & "," & p2.X & "," & p2.Y
            dr.Save()
            Vars("DataRowToDraw") = dr
            e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮绘制四边形
            e.Form.Controls("btnRectangle").PerformClick() '继续绘制下一个
        End If
    Case "btnCircle"
        If gps.Count = 0 Then
            gps.Add(curPoint)
            tipMark.Marker.Caption = "单击确定半径"
        Else
            Dim p1 As GeoPoint = gps(0)
            Dim p2 As GeoPoint = curPoint
            Dim dr As DataRow = DataTables("涂鸦").AddNew()
            dr("类型") = "Circle"
            dr("数据") = p1.X & "," & p1.Y & "," & p2.X & "," & p2.Y
            dr.Save()
            Vars("DataRowToDraw") = dr
            e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮绘制圆形
            e.Form.Controls("btnCircle").PerformClick() '继续绘制下一个
        End If
End Select

7、Map控件的DoubleClick事件代码:

Dim map As GeoMap = e.Sender.GeoMap
Dim layer As VectorLayer = map.Layers(0)
Select Case Vars("CurrentButton")
    Case "btnLine", "btnPolygon"
        Dim gps As List(Of GeoPoint) = Vars("GeoPointsClicked")
        If gps.Count > 2 OrElse (gps.Count = 2 AndAlso vars("CurrentButton") = "btnLine") Then '线条至少两个点,多边形至少三个点
            Dim sb As New StringBuilder() '将经纬度数据转成字符串形式
            For Each gp As GeoPoint In gps
                sb.Append(gp.X & "," & gp.Y & ",")
            Next
            Dim dr As DataRow = DataTables("涂鸦").AddNew()
            If vars("CurrentButton") = "btnLine" Then
                dr("类型") = "Line"
            Else
                dr("类型") = "Polygon"
            End If
            dr("数据") = sb.ToString().Trim(",")
            dr.Save()
            Vars("DataRowToDraw") = dr '准备根据这一行绘制形状
            e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮绘制形状
            e.Form.Controls(Vars("CurrentButton")).PerformClick() '继续绘制下一个
        End If
End Select

8、Map控件的MouseDown事件代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim ifo As HitTestInfo = map.HitTest(e.Sender.MousePosition)
If Vars("CurrentButton") = "btnSelect" Then
    If ifo IsNot Nothing AndAlso ifo.Vector IsNot Nothing Then
        If TypeOf ifo.Vector.tag Is DataRow Then
            vars("AdjustMark") = Nothing '按下的是形状本身,而不是调整标记,所以将调整标记设置为Nothing
            Vars("StartPoint") = map.MouseGeoPosition() '记录鼠标开始位置
            If Vars("VectorItemSelected") IsNot ifo.Vector Then '如果选择的是之前选定的形状
                e.Form.Controls("btnUnSelect").PerformClick() '取消之前选择的形状
                Vars("VectorItemSelected") = ifo.Vector '选中此形状
                ifo.Vector.Style.Stroke.Color = Color.Red '改变此形状的样式:
                If TypeOf ifo.Vector Is VectorPlacemark Then
                    ifo.Vector.Style.BackColor = Color.Red
                ElseIf TypeOf ifo.Vector Is VectorPolygon Then
                    ifo.Vector.Style.BackColor = Color.FromArgb(38, 255, 0, 0)
                End If
                e.Form.Controls("btnDrawAdjustMarks").PerformClick()
            End If
            Return
        ElseIf ifo.Vector.tag = "adjust" Then
            Dim mark As VectorPlacemark = vars("AdjustMark")
            If mark IsNot Nothing Then '复原当前调整标记的样式
                mark.Style.BackColor = Color.Red
                mark.Style.Stroke.Color = Color.Red
            End If
            vars("AdjustMark") = ifo.Vector '将单击的调整标记设置为当前调整标记
            Vars("StartPoint") = map.MouseGeoPosition() '记录鼠标开始位置
            ifo.Vector.Style.BackColor = Color.Blue '当前调整标记要有不同的样式
            ifo.Vector.Style.Stroke.Color = Color.Blue
            Return
        End If
    End If
    e.Form.Controls("btnUnSelect").PerformClick() '取消之前选择的形状
End If

9、Map控件的MouseMove事件代码:

If e.Button = MouseButtons.Left Then '如果移动过程按下了鼠标左键
    If Vars("CurrentButton") = "btnSelect" Then '且当前按钮为"选择"
        If Vars("AdjustMark") IsNot Nothing Then '如果拖动的是调整标记
            e.Form.Controls("btnAdjust").PerformClick() '调用调整按钮,调整形状打下和位置
        Else
            e.Form.Controls("btnMove").PerformClick() '调用移动按钮移动形状
        End If        
    End If
    Return '退出
End If
Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim tipMark As VectorPlacemark = Vars("TipMark")
If tipMark.Visible Then '提示标记跟随鼠标移动
    tipMark.Geometry = map.MouseGeoPosition
End If
Select Case vars("CurrentButton")
    Case "btnLine", "btnPolygon", "btnCircle", "btnRectangle"
        '调用"临时绘制"按钮绘制一个临时形状,用于告知用户你即将绘制的形状是怎样的
        '绘制过程可以按Esc键取消
        e.Form.Controls("btnTempDraw").PerformClick()
End Select

10、Map控件的MouseMove事件代码:

Vars("StartPoint") = Nothing '清除鼠标起始位置

11、Map控件的KeyDown事件:

If e.KeyCode = keys.Escape Then
     e.Form.Controls("btnSelect").PerformClick()
 ElseIf e.KeyCode = Keys.Delete Then
     e.Form.Controls("btnDelete").PerformClick()
End If

12、调整形状(btnAdjust)按钮代码:

If Vars("VectorItemSelected") Is Nothing OrElse Vars("StartPoint") Is Nothing OrElse Vars("AdjustMark") Is Nothing Then
    Return
End If
Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
'移动调整标记到鼠标位置,然后根据所有标记的位置计算得出形状的经纬度数据(字符串形式)
Dim mark As VectorPlacemark = Vars("AdjustMark")
mark.Geometry = map.MouseGeoPosition '将调整标记移到新位置
Dim sb As New StringBuilder()
Dim marks As List(Of VectorPlacemark) = Vars("AdjustMarks")
For Each mark In marks
    Dim pt As GeoPoint = mark.Geometry
    If sb.Length > 0 Then
        sb.Append(",")
    End If
    sb.Append(pt.X & "," & pt.Y)
Next
'所谓调整,其实就是根据新数据重新绘制一个形状,并移除原来的形状
Dim itemOld As VectorItem = Vars("VectorItemSelected") '获得选择的形状
layer.Items.Remove(itemOld) '移除原形状
Dim dr As DataRow = itemOld.Tag '获取数据行
dr("数据") = sb.ToString() '保存经纬度数据
Vars("DataRowToDraw") = dr '准备根据新的数据重新生成形状
e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮生成并绘制一个新形状
Dim itemNew As VectorItem = Vars("VectorItemDrawn") '获得刚刚生成的新形状
itemNew.Style.Stroke.Color = itemOld.style.Stroke.Color '新形状和原形状的边框被背景颜色一致
itemNew.Style.BackColor = itemOld.Style.BackColor
Vars("VectorItemSelected") = itemNew '将新形状设置为选中
'确保调整标记始终显示在形状前面:
layer.Items.Remove(itemNew)
layer.Items.Insert(layer.Items.IndexOf(marks(0)), itemNew)

13、移动(btnMove)按钮代码:

'这里的移动,其实就是根据新数据生成一个新形状,并移除原来的形状
If Vars("VectorItemSelected") Is Nothing OrElse Vars("StartPoint") Is Nothing Then
    Return
End If
Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim itemOld As VectorItem = Vars("VectorItemSelected") '获得之前选择的形状
Dim startPoint As GeoPoint = Vars("StartPoint") '获得鼠标起始位置
Dim currentPoint As GeoPoint = map.MouseGeoPosition '获得当前鼠标位置
Dim offsetX As Double = currentPoint.X - startPoint.X '水平位移
Dim OffsetY As Double = currentPoint.Y - startPoint.Y '垂直位移
Dim dr As DataRow = itemOld.Tag '获取形状对应的数据行
Dim vals() As String = dr("数据").ToString().Split(",") '拆分字符型的经纬度数据
Dim sb As New StringBuilder()
For i As Integer = 0 To vals.Length - 1 Step 2 '更新经纬度数据
    If sb.Length > 0 Then
        sb.Append(",")
    End If
    sb.Append(CDbl(vals(i)) + offsetX)
    sb.Append(",")
    sb.Append(CDbl(vals(i + 1)) + offsetY)
Next
dr("数据") = sb.ToString() '保存经纬度数据
Vars("DataRowToDraw") = dr
e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮生成并绘制一个新形状
Dim itemNew As VectorItem = Vars("VectorItemDrawn") '获得刚刚生成的新形状
itemNew.Style.Stroke.Color = itemOld.style.Stroke.Color '新形状和原形状的边框被背景颜色一致
itemNew.Style.BackColor = itemOld.Style.BackColor
layer.Items.Remove(itemOld) '移除原形状
Vars("VectorItemSelected") = itemNew '将新形状设置为选中
Vars("StartPoint") = currentPoint '更新鼠标起始位置
e.Form.Controls("btnDrawAdjustMarks").PerformClick() '绘制调整标记

14、标准绘制(btnDrawItem)按钮代码:

If Vars("DataRowToDraw") Is Nothing Then Return
Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim dr As DataRow = Vars("DataRowToDraw") '获取要绘制的数据行
Vars("DataRowToDraw") = Nothing
Select Case dr("类型")
    Case "Mark" '绘制标记
        Dim mark As VectorPlacemark = map.CreatePlaceMark(dr("数据"))
        mark.Marker.Shape = MarkerShape.Circle
        mark.Style.BackColor = Color.Green
        mark.Style.Stroke.Color = Color.Green
        mark.Marker.Size = New SizeF(6, 6)
        layer.Items.Add(mark)
        mark.Tag = dr
        Vars("VectorItemDrawn") = mark '绘制好的形状存储在var变量中,方便调用者使用
    Case "Line" '绘制线条
        Dim line As VectorPolyline = map.CreateLine(dr("数据"))
        line.Style.Stroke.Color = Color.Green
        line.Style.Stroke.Width = 2
        layer.Items.Add(line)
        line.Tag = dr
        Vars("VectorItemDrawn") = line
    Case "Polygon", "Circle", "Rectangle" '绘制多边形、圆形和四边形
        Dim polygon As VectorPolygon
        If dr("类型") = "Polygon" Then
            polygon = map.CreatePolygon(dr("数据"))
        ElseIf dr("类型") = "Circle" Then
            polygon = map.CreateCircle(dr("数据"), True)
        Else
            polygon = map.CreateRectangle(dr("数据"))
        End If
        polygon.Style.Stroke.Color = Color.Green
        polygon.Style.BackColor = Color.FromArgb(38, 0, 255, 0)
        layer.Items.Add(polygon)
        polygon.Tag = dr
        Vars("VectorItemDrawn") = polygon
End Select

15、绘制临时形状(btnTempDraw)按钮代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim gps As New List(Of GeoPoint) '创建一个临时的位置点集合,避免影响用于正式绘制的数据
gps.AddRange(Vars("GeoPointsClicked")) '将已经确认的位置点添加到临时集合中
gps.Add(map.MouseGeoPosition) '鼠标位置的点要参与绘制,所以也添加到临时集合中
Dim TempVectorItem As VectorItem = Nothing
If gps.Count > 1 Then
    Select Case vars("CurrentButton") '绘制新的临时形状
        Case "btnLine", "btnPolygon"
            TempVectorItem = map.CreateLine(gps)
        Case "btnRectangle"
            TempVectorItem = map.CreateRectangle(gps(0), gps(1))
        Case "btnCircle"
            TempVectorItem = map.CreateCircle(gps(0), gps(1), True)
    End Select
    If TempVectorItem IsNot Nothing Then '设置临时形状的样式
        TempVectorItem.Style.Stroke.Color = Color.RosyBrown
        TempVectorItem.Style.Stroke.Width = 2
        layer.Items.Add(TempVectorItem)
    End If
End If
If Vars("TempVectorItem") IsNot Nothing Then '移除原来的临时形状
    layer.Items.Remove(Vars("TempVectorItem"))
End If
Vars("TempVectorItem") = TempVectorItem '将新的临时形状存储在Var变量中

16、绘制调整标记(btnDrawAdjustMarks)按钮代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim AdjustMarks As List(Of VectorPlacemark) = Vars("AdjustMarks")
For Each mark As VectorPlacemark In AdjustMarks '移除原来的调整标记
    layer.Items.Remove(mark)
Next
If vars("AdjustState") = True AndAlso Vars("VectorItemSelected") IsNot Nothing Then
    Dim curItem As VectorItem = Vars("VectorItemSelected")
    Dim dr As DataRow = curItem.Tag
    If dr("类型") = "Mark" Then Return '标记本身不需要调整标记的,所以退出
    Dim strVals() As String = dr("数据").ToString().Split(",")
    AdjustMarks.Clear() '清除原来的调整标记
    For idx As Integer = 0 To strVals.Length - 2 Step 2 '绘制新的调整标记
        Dim x As Double = CDbl(strVals(idx))
        Dim y As Double = CDbl(strVals(idx + 1))
        Dim mark As New VectorPlacemark
        mark.Tag = "adjust" '将Tag设置为"adjust",表明这是一个调整标记
        mark.Geometry = New GeoPoint(x, y)
        mark.Marker.Size = New SizeF(8, 8)
        mark.Marker.Shape = MarkerShape.Circle
        mark.Style.BackColor = Color.Red
        mark.Style.Stroke.Color = Color.Red
        layer.Items.Add(mark)
        AdjustMarks.Add(mark)
    Next
End If

17、插入点(btnInsertPoint)按钮代码:

'一个调整标记对应一个点,知道这一点,就很好处理
If Vars("VectorItemSelected") Is Nothing Then
    MessageBox.Show("请先选择一个形状!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Return
End If
If Vars("AdjustMark") Is Nothing Then
    MessageBox.Show("请先选择要插入的位置!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Return
End If
Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim marks As List(Of VectorPlacemark) = Vars("AdjustMarks") '获取调整标记集合
Dim mark As VectorPlacemark = Vars("AdjustMark") '获取当前调整标记,在该标记之后插入点
Dim insertIndex As Integer '插入位置
Dim startPoint As GeoPoint '将在startPoint和endPoint之间插入
Dim endPoint As GeoPoint
Dim dr As DataRow = Vars("VectorItemSelected").tag '获取数据行
If dr("类型") <> "Line" AndAlso dr("类型") <> "Polygon" Then
    MessageBox.Show("只有线条和多边形才可以插入点!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Return
End If
If mark Is marks(0) Then '如果当前点是首点
    If dr("类型") = "Line" Then
        MessageBox.Show("不可以在线条首点之前插入!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
        Return
    Else '多变形是闭环的,首点的前一个点其实就是最后一个点
        startPoint = marks(marks.Count - 1).Geometry
        endPoint = marks(0).Geometry
        insertIndex = 0
    End If
Else '如果不是首点
    For index As Integer = 1 To marks.Count - 1 '遍历确认插入位置
        If marks(index) Is mark Then
            startPoint = marks(index - 1).Geometry
            endPoint = marks(Index).Geometry
            insertIndex = index
            Exit For
        End If
    Next
End If
Dim insertCount As Integer = 1 '插入点数
If InputValue(insertCount, "插入点", "请输入要插入的点数:") = False Then
    Return
End If
For i As Integer = insertCount To 1 Step - 1 '现在开始插入点(其实也是插入调整标记)
    Dim x As Double = startPoint.X + (endPoint.X - startPoint.X) / (insertCount + 1) * i
    Dim y As Double = startPoint.Y + (endPoint.Y - startPoint.Y) / (insertCount + 1) * i
    mark = New VectorPlacemark
    mark.Tag = "adjust" '将Tag设置为"adjust",表明这是一个调整标记
    mark.Geometry = New GeoPoint(x, y)
    mark.Marker.Size = New SizeF(8, 8)
    mark.Marker.Shape = MarkerShape.Circle
    mark.Style.BackColor = Color.Red
    mark.Style.Stroke.Color = Color.Red
    layer.Items.Add(mark)
    marks.Insert(insertIndex, mark)
Next
'保存经纬度数据:
Dim sb As New StringBuilder()
For Each mark In marks
    Dim pt As GeoPoint = mark.Geometry
    If sb.Length > 0 Then
        sb.Append(",")
    End If
    sb.Append(pt.X & "," & pt.Y)
Next
dr("数据") = sb.ToString()

18、删除点按钮代码:

'一个调整标记对应一个点,知道这一点,就很好处理
If Vars("VectorItemSelected") Is Nothing Then
    MessageBox.Show("请先选择一个形状!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Return
End If
If Vars("AdjustMark") Is Nothing Then
    MessageBox.Show("请先选择要删除的点!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Return
End If
Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
Dim ItemSelected As VectorItem = Vars("VectorItemSelected") '获得选定的形状
Dim dr As DataRow = ItemSelected.Tag '获得数据行
Dim marks As List(Of VectorPlacemark) = Vars("AdjustMarks") '获取调整标记集合
Dim mark As VectorPlacemark = Vars("AdjustMark") '获取当前调整标记(即将被删除的点)
If dr("类型") = "Line" AndAlso marks.Count = 2 Then
    MessageBox.Show("搞什么啊,线条至少要有两个点!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
    Return
End If
If dr("类型") = "Polygon" AndAlso marks.Count = 3 Then
    MessageBox.Show("别犯糊涂,多边形至少要有三个点!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
    Return
End If
Dim sb As New StringBuilder()
Dim index As Integer '被删除点的位置
For i As Integer = 0 To marks.Count - 1 '获取被删除点的位置,并重新生成排除删除点后的新经纬度数据
    If marks(i) Is mark Then
        index = i
    Else
        Dim pt As GeoPoint = marks(i).Geometry
        If sb.Length > 0 Then
            sb.Append(",")
        End If
        sb.Append(pt.X & "," & pt.Y)
    End If
Next
marks.Remove(mark) '从集合中移除被删除点
layer.Items.Remove(mark) '从map控件中移除被删除的点
dr("数据") = sb.ToString() '保存数据
Vars("DataRowToDraw") = dr '传递新数据,准备重新绘制生成一个新形状
e.Form.Controls("btnDrawItem").PerformClick() '调用绘制按钮生成并绘制一个新形状
Dim itemNew As VectorItem = Vars("VectorItemDrawn") '获得刚刚生成的新形状
itemNew.Style.Stroke.Color = ItemSelected.style.Stroke.Color '新形状和原形状的边框被背景颜色一致
itemNew.Style.BackColor = ItemSelected.Style.BackColor
layer.Items.Remove(ItemSelected) '移除原形状
Vars("VectorItemSelected") = itemNew '将新形状设置为选中
layer.Items.Remove(itemNew) '确保调整标记始终显示在形状前面
layer.Items.Insert(layer.Items.IndexOf(marks(0)), itemNew)
'选中下一个调整标记作为当前调整标记:
index = Math.Min(index, marks.Count - 1)
mark = marks(index)
mark.Style.BackColor = Color.Blue
mark.Style.Stroke.Color = Color.Blue
Vars("AdjustMark") = mark

19、取消选择(btnUnSelect)按钮代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
If Vars("VectorItemSelected") Is Nothing Then Return
Dim ItemSelected As VectorItem = Vars("VectorItemSelected") '获取之前选择形状
ItemSelected.Style.Stroke.Color = Color.Green '回复默认样式
If TypeOf ItemSelected Is VectorPlacemark Then
    ItemSelected.Style.BackColor = Color.Green
ElseIf TypeOf ItemSelected Is VectorPolygon Then
    ItemSelected.Style.BackColor = Color.FromArgb(38, 0, 255, 0)
End If
Vars("VectorItemSelected") = Nothing '取消选择
Vars("AdjustMark") = Nothing
For Each mark As VectorPlacemark In Vars("AdjustMarks")
    layer.Items.Remove(mark)
Next
Vars("AdjustMarks").Clear()
e.Form.Controls("btnDrawAdjustMarks").PerformClick()

20、删除(btnDelete)按钮代码:

Dim map As GeoMap = e.Form.Controls("Map1").GeoMap
Dim layer As VectorLayer = map.Layers(0)
If Vars("VectorItemSelected") IsNot Nothing Then
    Dim ItemSelected As VectorItem = Vars("VectorItemSelected") '获取选择的形状  
    Dim dr As DataRow = ItemSelected.Tag '获取形状对应的数据行
    dr.Delete() '删除数据行
    e.Form.Controls("btnUnSelect").PerformClick() '模拟取消选择
    layer.Items.Remove(ItemSelected) '移除形状
    Vars("VectorItemSelected") = Nothing
    Vars("StartPoint") = Nothing
End If
e.Form.Controls("btnSelect").PerformClick() '模拟单击选择按钮
e.Cancel = True '已经没必要执行窗口的全局Click事件了


本页地址:http://www.foxtable.com/webhelp/topics/6168.htm