MapObject学习笔记-第六讲 MO中的坐标和坐标系
第六讲 MO中的坐标和坐标系
一、坐标系对象
1、坐标对象概述
MO中提供了一系列坐标系对象(也称为投影对象)来控制和操作地图的坐标系统,如projcoordsys(投影坐标系统)、Geocoordsys(地理坐标系统)、Datum(基准面)、PrimeMeridian(本初子午线)、Projection(投影)、Spheroid(地球椭圆体)、Unit(单位)、Geotransformton(地理坐标转换)等。
这些对象都可以在程序中定义,例如:Dim thePrime As New MapObjects2.PrimeMeridian
投影对象之间的部分关系如图所示。一个Datum对象有Spheroid属性,Geocoordsys对象包括有Datum和PrimeMeridian属性。
在MO中,坐标系的产生和转换是用POSC(Petrochemical open software consortium)模型来管理的,这个模型定义了不同的测量和绘图坐标系与他们之间的关系。在POSC模型下的每个对象都有一个唯一的坐标系编码(利用Type属性操作),它定义了该对象在POSC模型下的坐标系属性(CoordinateSystem)。
设置和改变对象的CoordinateSystem属性,会改变图形的外观。Geotransformton对象可以转换MapLayer的投影方式,也可以转换单个图形对象。
2、地理坐标系和投影坐标系
在MO中,每个MAP或MapLayer对象都和一个坐标系对象发生联系,这个坐标系对象是地理坐标系对象(Geocoordsys),也可以是投影坐标系(projcoordsys)对象。
地理坐标系(Geocoordsys)是MO中最常用的坐标系对象,它用经纬度描述地面上的位置。描述位置时,用Datum属性来设置基准面,用PrimeMeridian属性来设置其本初子午线,用Unit属性设置其坐标系单位。
标准的地理坐标系的改变可以通过用Type属性来设置GeographicCoordSys常数完成,通过设置其Geocoordsys、PrimeMeridian和Unit属性,也可以设置自定义的投影坐标系。
投影坐标系(projcoordsys)用X和Y坐标来描述地面上的位置,它用地球椭圆体Spheroid模拟地球,用Projctedcoordsys属性表示投影坐标系的来源,用Projection属性表示投影的计算方法,用Unit属性设置其坐标系单位。
标准的投影坐标系的改变可以通过用Type属性来设置ProjectedCoordSys常数来完成,通过设置其Projctedcoordsys、Projection和Unit属性,也可以设置自定义的投影坐标系。
地理坐标系和投影坐标系可以用在MapLayer图层和MAP上,通过使用Transform方法,还可以改变单个图形对象的坐标系。下面的示例程序来判断图层所采用的坐标系,利用到了IsProjected属性:
Option Explicit
Dim dc As New DataConnection
Dim layer As MapObjects2.MapLayer
Private Sub layset()
dc.Database = App.Path + "\..\" + "world"
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("country")
layer.Symbol.Color = moOrange
Map1.Layers.Add layer
Map1.Refresh
End Sub
Private Sub Command1_Click()
Dim coordsys As Object
Dim a As String
Set layer = Map1.Layers(0)
Set coordsys = layer.CoordinateSystem
If coordsys.IsProjected Then
a = MsgBox("图层为投影坐标系", , "坐标信息显示框")
ElseIf Not coordsys.IsProjected Then
a = MsgBox("图层为地理坐标系", , "坐标信息显示框")
End If
End Sub
Private Sub Form_Load()
Command1.Caption = "显示坐标信息"
layset
End Sub
3、坐标系的读取和设置
反映其坐标类型的CoordinateSystem属性可以用以下方法来读取:
layer.CoordinateSystem.Name’坐标系名称
layer.CoordinateSystem.Type’坐标系代码
设置MapLayer或Map的CoordinateSystem时,要先定义一个坐标对象,再设置它的Type属性,最后才可以设置CoordinateSystem。如:
Dim mapGCS As New MapObjects2.GeoCoordSys
mapGCS.Type = moGeoCS_Adindan
Map1.CoordinateSystem = mapGCS
图层文件在制作时带有一个坐标系的信息文件,即.prj文件。下面这个例子是显示一个带有坐标系文件的图层,再设置一个不带有坐标系文件的图层的坐标系信息。示例代码:
Option Explicit
Dim dc As New DataConnection
Dim layer As MapObjects2.MapLayer
Dim mapPCS As MapObjects2.ProjCoordSys
Dim mapgCS As New MapObjects2.GeoCoordSys
Private Sub layset()
dc.Database = App.Path + "\..\" + "world"
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("country")
layer.Symbol.Color = moOrange
Map1.Layers.Add layer
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("cities")
layer.Symbol.Color = moGreen
layer.Symbol.Size = 3
Map1.Layers.Add layer
Map1.Refresh
End Sub
Private Sub Command1_Click()
Set layer = Map1.Layers(0)
If Map1.Layers(1).CoordinateSystem.IsProjected Then
mapPCS.Type = Map1.Layers(1).CoordinateSystem.Type
layer.CoordinateSystem = mapPCS
ElseIf Not Map1.Layers(1).CoordinateSystem.IsProjected Then
mapgCS.Type = Map1.Layers(1).CoordinateSystem.Type
layer.CoordinateSystem = mapgCS
End If
List1.Clear
addlist
layset
End Sub
Private Sub addlist()
Dim curlayer As MapObjects2.MapLayer
For Each curlayer In Map1.Layers
If Not curlayer.CoordinateSystem Is Nothing Then
List1.AddItem curlayer.Name & ":" & curlayer.CoordinateSystem.Name
Map1.Layers(curlayer.Name).Visible = True
Else
List1.AddItem curlayer.Name & ":坐标系没有设置!"
Map1.Layers(curlayer.Name).Visible = False
End If
Next curlayer
List1.AddItem "Map控件:" & Map1.CoordinateSystem.Name
End Sub
Private Sub Form_Load()
layset
Command1.Caption = "改变"
If Map1.CoordinateSystem Is Nothing Then
If Map1.Layers(1).CoordinateSystem.IsProjected Then
Dim mapPCS As New MapObjects2.ProjCoordSys
mapPCS.Type = Map1.Layers(1).CoordinateSystem.Type
Map1.CoordinateSystem = mapPCS
ElseIf Not Map1.Layers(1).CoordinateSystem.IsProjected Then
Dim mapgCS As New MapObjects2.GeoCoordSys
mapgCS.Type = "4326"
Map1.CoordinateSystem = mapgCS
End If
End If
addlist
End Sub
4、坐标系的改变
当改变坐标系时,地图的形状也会发生改变,下面是一个世界地图转换的例子:
Dim dc As New DataConnection
Dim layer As MapObjects2.MapLayer
Private Sub Command1_Click()
Dim csmap As New MapObjects2.ProjCoordSys
'Map1.Layers(0).CoordinateSystem = Map1.Layers(1).CoordinateSystem
csmap.Type = moProjCS_World_WinkelI
Map1.CoordinateSystem = csmap
End Sub
Private Sub Command2_Click()
Map1.CoordinateSystem = Map1.Layers(1).CoordinateSystem.Type
End Sub
Private Sub Form_Load()
Command1.Caption = "投影坐标系"
Command2.Caption = "地理坐标系"
layset
End Sub
Private Sub layset()
dc.Database = App.Path + "\..\" + "world"
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("country")
layer.Symbol.Color = moBlue
Map1.Layers.Add layer
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("latlong")
layer.Symbol.Color = moBlack
layer.Symbol.Size = 1
Map1.Layers.Add layer
Map1.Refresh
End Sub
二、地图上坐标单位及其转换
1、在地图上显示经纬度
点击地图查看坐标时,如果不作任何的坐标转换,在Map1_MouseDown过程中X和Y的显示坐标为控件的原始坐标(twips)。用ToMapDsitance和ToMapPoint方法,可以把点击坐标转换成地图坐标。
ToMapDsitance是地图控件的成员函数之一,其功能是将屏幕坐标的距离值转换为地图坐标系的距离值,语法为object.ToMapDistance distance,返回值是地图坐标系的距离值,distance为屏幕坐标的距离值。
下面程序是将世界地图进行图上坐标向经纬度转换的示例,用ToMapDsitance方法时,地图从左到右为0-360度,从上到下为0-180度。用ToMapPoint方法时,考虑了Datum和PrimeMeridian属性,从伦敦开始向右为正(0-180),向左为负(-180-0),从赤道向上为0-90,向下为-90-0。代码如下:
Dim dc As New DataConnection
Dim layer As MapObjects2.MapLayer
Private Sub Command1_Click()
Dim mapGCS As New MapObjects2.GeoCoordSys
mapGCS.Type = Map1.Layers(1).CoordinateSystem.Type
MsgBox "datum = " & mapGCS.Datum.Name & " ,primemridian= " & mapGCS.PrimeMeridian.Name
End Sub
Private Sub Form_Load()
Label1.Caption = "点击地图显示经纬度"
layset
Command1.Caption = "显示坐标信息"
Option1.Caption = "ToMapDsitance"
Option2.Caption = "ToMapPoint"
End Sub
Private Sub layset()
dc.Database = App.Path + "\..\" + "world"
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("country")
layer.Symbol.Color = moBlue
Map1.Layers.Add layer
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("latlong")
layer.Symbol.Color = moBlack
layer.Symbol.Size = 1
Map1.Layers.Add layer
Map1.Refresh
End Sub
Private Sub Map1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim str1 As String
Dim p1 As MapObjects2.Point
If Not Option1 Then
Set p1 = Map1.ToMapPoint(X, Y)
str1 = "x=" & Format(p1.X, "0.000") & ",y=" & Format(p1.Y, "0.000")
Else
str1 = "x=" & Format(Map1.ToMapDistance(X), "0.000") & ",y=" & Format(Map1.ToMapDistance(Y), "0.000")
End If
Label1.Caption = str1
Dim rec As MapObjects2.Rectangle
If Button = 1 Then
Set Map1.Extent = Map1.TrackRectangle
Else
Map1.Pan
Map1.Refresh
End If
End Sub
2、在地图上显示公里
地球的赤道直径为
Dim dx As Single
Dim dc As New DataConnection
Dim layer As MapObjects2.MapLayer
Private Sub Form_Load()
dx = 40075.7 / 360
Label1.Caption = "点击地图显示公里"
layset
End Sub
Private Sub layset()
dc.Database = App.Path + "\..\" + "world"
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("country")
layer.Symbol.Color = moBlue
Map1.Layers.Add layer
Set layer = New MapLayer
Set layer.GeoDataset = dc.FindGeoDataset("latlong")
layer.Symbol.Color = moBlack
layer.Symbol.Size = 1
Map1.Layers.Add layer
Map1.Refresh
End Sub
Private Sub Map1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim str1 As String
str1 = "x=" & Format(Map1.ToMapDistance(X) * dx, "0.000") & ",y=" & Format(Map1.ToMapDistance(Y) * dx, "0.000")
Label1.Caption = str1
End Sub