GIS软件开发技术
第一章MapObjects基础Gis常用开发平台
MapObjects简介
?MapObjects功能
?MapObjects优点
?MapObjects基础
编程规范
01、Gis软件开发常用开发平台
常用开发平台的比较:
VB:较易入门
VBA:对于扩充原有功能较好。如AutoCAD、ArcMap中的VBA。开发效率最高的一种开发方式(常常是一个语名即可实现其它开发工具要几十甚至上百行的代码才能实现的功能)。缺点是所开发出的应用程序不能脱离相应的运行环境。(如在ArcMap中开发的应用程序,必须先要安装ArcMap)
VC++:较为灵活,开发资料众多。可实现对系统的全面操作。缺点是学习起来较难,所开发出的应用程序常常会产生难以预计的错误。(如内存泄露等)
Delphi:可扩充性最好,现已有上万个带源码的控件可供使用,几乎涉及到各各方面。如数据库控件InfoPower3000、OpenGL控件GLScene,工业控制控件等。
GIS组件简介:
MapObjects:ESRI
1、可实现功能:
2、可使用的数据
ArcView Gis Shapefiles:创建新层、读写数据,添加删除记录与几何要素
ArcSDE:不能创建新层
Arcinfo Coverages:只读
CAD格式及VPF数据库:只读(Vector Product Format是一种标准的基于空间关
系数据模型的大型空间数据库的格式、结构与组织。是美国国防部的标准)
外部数据库:只读
ArcObjects:ESRI
MapX:Mapinfo
Supermap:中科院地理所
一般用户(大多数用户)关心的问题:应用程序的运行速度与稳定性。不关心所采用的开发工具及内部实现方式。只有特殊用户(少量用户)考虑与原有系统的兼容性才关心开发平台。
软件开发中应注意的问题:
代码的规范性:1、命名约定2、代码缩进3、逻辑关系的排列次序
对于较为普通的问题尽量使用较常见的解决方式。尽量不使用较为古怪的技巧(如:两数的交换),这样会降低代码的可读性。
Delphi开发环境简介:
1、数据库应用
2、OpenGL应用
3、报表制作
02、通用GIS功能的界面框架设计
1、菜单的设计
2、工具条的设计
3、状态栏提示信息的显示(标准控件及1stClass控件的使用)
4、fcLookoutBar控件的使用
5、TActionList控件的使用
6、图标及标题的设置
03、MapObjects的模块间关系简介
属性、事件、方法:
属性:对象的性质,方法:对象的动作,事件:对象的响应。(只有
Map Control有事件)
可创建对象与不可创建对象
为有效地使用MapObjects中的OLE Automation对象,必须注意一些对象可以创建,一些对象不可创建。如果某个对象可以创建,在对象图中对象名称下有一个Creatable标注。
如一个对象可以创建可用如下代码创建:(假设创建点对象)
Dim NewObject as New MapObjects2.Point
或
Dim NewObject as MapObjects2.Point
Set NewObject = New MapObjects2.Point
在将对象的引用赋给变量、数据类型的元素或可写对象的属
性时,须使用关键字Set;在创建对象的实例时,须使用关
键字New
Var
NewObject: ImoPoint;
Begin
NewObject := coPoint.Create;
End;
在Delphi中如一个对象可创建,可用coXXX.Create方法进
行创建。XXX为可创建对象名
值传递与引用传递:
值传递:新的变量得到原始数据或对象的一个拷贝,其值的改变不影响原值。Name属性;引用传递:新的变量得到原始数据或对象的内存地址,其值的改变影响原值。Symbol属性
值传递
Dim LayerName As String
LayerName= https://www.360docs.net/doc/674034403.html,yers.Item(0).Name
LayerName = "MyLayerName"
MsgBox LayerName
MsgBox https://www.360docs.net/doc/674034403.html,yers.Item(0).Name
var
LayerName: string;
begin
LayerName := ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(0)).Name;
LayerName := 'MyLayerName';
ShowMessage(LayerName);
ShowMessage(ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(0)).Name);
End;
引用传递
Dim MySymbol As New MapObjects2.Symbol
Set MySymbol = https://www.360docs.net/doc/674034403.html,yers.Item(0).Symbol
MySymbol.Color = moRed
Map1.Refresh
var
MySymbol: imoSymbol;
begin
MySymbol := coSymbol.Create ;
MySymbol := ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(0)).Symbol;
MySymbol.Color := moRed;
Map1.Refresh ; end;
MapObjects中的常量:
常量均以mo开头。在编写代码时,可使用常量名也可使用常量左边的整数。但最好使用常量名称以增强代码的可读性。
MainMap.MousePointer = moArrow; 或MainMap.MousePointer = 1;
第二章地图与图层
M ap Control
L ayers Collection
?MapLayers
?ImageLayers
R ectangle、point
D ataConnection
G eoDatasets Collection
G eoDataset
T rackingLayer
查看地图
地图的放大、缩小、平移等操作
交互式方法:Pan、TrackRegtangle、TrackPolygon、TrackCircle。当使用上述方法时,运行时线程将暂停,等待用户使用鼠标与Map控件交互。
实现对地图的基本操作。(地图的放大、缩小、平移)
Private Sub MainMap_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
Dim r As new MapObjects2.Rectangle
If barDisplay.Buttons("Zoom in").Value = 1 Then
MainMap.Extent = MainMap.TrackRectangle
ElseIf barDisplay.Buttons("Zoom out").Value = 1 Then
r = MainMap.Extent
r.ScaleRectangle(1.25)
MainMap.Extent = r
ElseIf barDisplay.Buttons("Pan").Value = 1 Then
MainMap.Pan
ElseIf barDisplay.Buttons("Identify").Value = 1 Then
Call frmIdentify.Identify(x, y)
Endif
MainMap.Refresh
End sub procedure TMainFRM.MainMapMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
r: imoRectangle;
begin
if tbZoomIn.Down then
MainMap.Extent := MainMap.TrackRectangle
else
if tbZoomOut.Down then
begin
r := coRectangle.Create;
r := MainMap.Extent; //(Extent:为地图的空间区域
可理解为当前的显示范围)r.ScaleRectangle(1.25); //
MainMap.Extent := r;
end
else
if tbPan.Down then
MainMap.Pan
else
if (tbIdentify.Down) and (Button = mbLeft) then
// GetIdentify(X, Y) ;
MainMap.Refresh;
End;
获取鼠标坐标
在创建面向图形的应用程序时,必须解决两种坐标系统的转换问题:定义窗体中控件的尺寸与位置的控制坐标,以及定义在打印机或显示器上图形的大小与位置的设备坐标。MapObjects开发人员还须使用第三种坐标系统:地图坐标系统。此坐标定义了地图上几何要素或影像的笛卡尔位置。为保证有效,此坐标系统必须与某种投影或非投影坐标相匹配,以
定义物体在地表的位置。
在MapObjects中,ToMapPoint方法以参数形式接收MouseDown、MouseUp、MouseMove事件传递的鼠标位置的x,y参数。这些x,y值是以控制坐标来表达的。ToMapPoint 方法将窗体上点的位置转换成相应的地图上的点位置。FromMapPoint方法实现相反的转换。类式的方法有:ToMapDistance与FromMapDistance
Private Sub Map1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim MyPoint As New Point
Set MyPoint = Map1.ToMapPoint(X, Y)
Text1.Text = Str(MyPoint.X) + " " + Str(MyPoint.Y) End Sub procedure TForm1.Map1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
MyPoint: ImoPoint;
begin
MyPoint := coPoint.Create ;
MyPoint := Map1.ToMapPoint(x,y);
Edit1.Text := FloatToStr(MyPoint.X) + ' ‘+
FloatToStr(MyPoint.Y );
end;
图层集合(Layers)
?每个地图控件有且只有一个Layers集合
?Layers集合可包含MapLayer与ImageLayer两类地图文件?每个图层可有自已的显示方式
Dim i As Integer
For i = 0 To https://www.360docs.net/doc/674034403.html,yers.Count - 1 MsgBox https://www.360docs.net/doc/674034403.html,yers.Item(i).Name Next i var
i: integer;
MyLayers: imoLayers;
begin
MyLayers := https://www.360docs.net/doc/674034403.html,yers ;
for i := 0 to MyLayers.Count - 1 do
ShowMessage(ImoMapLayer(MyLayers.Item(i)).Name); end;
或:
var
i: integer;
begin
for i := 0 to https://www.360docs.net/doc/674034403.html,yers.Count - 1 do
ShowMessage(ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(i)).Name); end;
04、MapObjects图层操作
1、ArcView格式地图
2、AutoCAD图形
3、位图
注意观察如下图形中的红线部份:
加入ArcView格式地图
步骤:
1、生成数据连接对象(ImoDataConnection)
2、设定数据连接对象的DataBase属性
4、取得空间数据集
5、生成新的图层
6、将新生成的图层加入地图控件
Private Sub Command1_Click()
Dim dc As New MapObjects2.DataConnection
Dim lyr As New MapObjects2.MapLayer
dc.Database = "C:\USA"
If dc.Connect Then
Set lyr.GeoDataset = dc.FindGeoDataset("Counties") If lyr.Valid Then
https://www.360docs.net/doc/674034403.html,yers.Add lyr
Else
MsgBox "无法加入图层"
End If
Else
MsgBox "出错,请确定数据是否存在?"
End If
End Sub var
dc: imoDataConnection;
lyr: imoMapLayer;
begin
dc := coDataConnection.Create;
lyr := coMapLayer.Create;
dc.Database := 'C:\USA';
if dc.Connect then
begin
lyr.GeoDataset := dc.FindGeoDataset('Counties');
if lyr.Valid then
https://www.360docs.net/doc/674034403.html,yers.Add(lyr)
else
ShowMessage('无法加入图层')
end else
ShowMessage('出错,请确定数据是否存在?'); end;
注意要点:
DataBase:对于shapefile,数据库属性仅为一包含有shapefile的文件夹或目录字符串。FindGeoDataset:对于shapefile,参数字符串只须设为没有扩展名的ShapeFile文件名。较为完整的加入ShapeFile的Delphi代码:
function TMapManage.AddShapeFile(sFileName: string; LayerColor: integer = 16711680): string;
var
gs: IMoGeoDataset;
dc: IMoDataConnection;
name, fname: string;
Newlayer: IMoMapLayer;
begin
dc := IMoDataConnection(CreateOleObject('MapObjects2.DataConnection'));
// 或dc := coDataConnection.Create ;;
name := SFileName;
fname := ExtractFileDir(name); //获取某一文件所在的路径
dc.database := fname; //DataBase属性:指明所采用的数据,如为SDE则为数据库名,如为Shp文件则为Shp文件所在的目录
if not dc.connect then exit;
Name := GetFileName(Name);
if not LayerExist(Name) then
begin
gs := dc.FindGeoDataset(name);
gs.AllowSharing := true;
if VarIsEmpty(gs) then exit; //判断对象是否为空,(在Delphi6中此函数存在错误)
NewLayer := IMoMapLayer(CreateOleObject('MapObjects2.MapLayer'));
NewLayer.GeoDataset := gs;
NewLayer.Symbol.Color := LayerColor;
https://www.360docs.net/doc/674034403.html,yers.Add(NewLayer);
end
else begin
MessageBox(Handle, '已存在图层', '图层管理', MB_OK + MB_ICONINFORMA TION);
Result := '';
Exit;
end;
Result := Name;
end;
//假设sFileNmae 为C:\Projects\Lean.shp函数返回值为Lean
function GetFileName(sFileName: string): string;
begin
while pos('\', sFileName) > 0 do
begin
delete(sFileName, 1, 1);
end;
while pos('.', sFileName) > 0 do
delete(sFileName, Pos('.', sFileName), 4);
Result := sFileName;
end;
更正Delphi6中的VarIsEmpty函数:
将:
Result := FindVarData(V)^.VType = varEmpty;
改为:
with TVarData(V) do
Result := (VType = varEmpty) or ((VType = varDispatch) or
(VType = varUnknown)) and (VDispatch = nil);
//判断指定的图层是否存在
function LayerExist(sLayerName: string): boolean;
var
i: integer;
CurrentMap: ImoMapLayer;
begin
CurrentMap := CoMapLayer.Create;
for i := 0 to https://www.360docs.net/doc/674034403.html,yers.Count - 1 do
begin
CurrentMap := ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(i));
if https://www.360docs.net/doc/674034403.html, = sLayerName then
begin
Result := true;
exit;
end;
end;
Result := false;
end;
加入Coverage图层:
加入SDE图层
加入Image图层:
Private Sub Command1_Click()
Dim lyr As New MapObjects2.ImageLayer
lyr.File = "D:\ Washington\Wash.bmp" https://www.360docs.net/doc/674034403.html,yers.Add lyr
End Sub procedure TForm1.Button1Click(Sender: TObject); var
Lyr: imoImageLayer;
begin
lyr := coImageLayer.Create ;
Lyr.File_ := 'D:\ Washington\Wash.bmp';
https://www.360docs.net/doc/674034403.html,yers.Add(Lyr);
end;
注意要点:
与失量数据不同,在创建ImageLayer时不需要创建DataConnection和GeoDataset对象,中需设置ImageLayer对象实例的File属性,再将ImageLayer加入Map控件即可。
加入CAD文件:
Private Sub Command2_Click()
Dim dc As New MapObjects2.DataConnection
Dim lyr As New MapObjects2.MapLayer
dc.Database = "[CADPoint]D:\\ARCVIEW\CAD"
Set lyr.GeoDataset = dc.FindGeoDataset("Parcels.dwg")
https://www.360docs.net/doc/674034403.html,yers.Add lyr
End Sub procedure TForm1.Button3Click(Sender: TObject); var
dc: imoDataConnection;
Lyr: imoMapLayer;
begin
dc := coDataConnection.Create ;
Lyr := coMapLayer.Create ;
dc.Database := '[CADPoint]D:\ ARCVIEW\CAD'; lyr.GeoDataset := dc.FindGeoDataset('Parcels.dwg');
https://www.360docs.net/doc/674034403.html,yers.Add(Lyr);
end;
注意要点:
DataConnection的Database属性字符串不仅要提供文件所在的路径,而且要包括实体类型的前缀。如[CADPoint]、[CADArea]及[CADText]等,前缀[CAD]默认为线实体。
在使用FindGeoDataset方法时,其参数必须包括扩展名在内的完整文件名。
小结:
测试数据库联接:
Connect与DisConnect:
Connect与DisConnect是作用在DataConnection对象上的方法。Connected与ConnectErr 是DataConnection对象的属性,可以在任何时间读取检验连接状态。
Connect首先读取数据库属性,确定数据的存储位置;读取存储的文件并创建数据的GeoDataset集合;Connect返回一布尔值,并在Connected属性中写入这一布尔值;若Connect 返回的布尔值为False,它将设置ConnectError的值。
DisConnect方法释放DataConnection对象和数据存储位置间的连接,清空GeoDataSets 集合,并重新设置Connected值为False。
加入图层时应注意到不同类型的数据其DataConnection的DataBase属性字符串的值格式不同。
文件类型DataConnection的Database属性DataConnection的FindGetDataset方法ShapeFile:Shp文件所在的路径不带扩展名的Shp文件名
AutoCAD:[类型]+CAD文件所在的路径包括扩展名在内的完整文件名
Image:不需要设置不需要设置
Coverage:
05、图层的显示次序
图层在地图控件的次序决定或影响整个地图的显示效果,点状信息或线状信息常常会被面状信息所掩盖。可通过Layers集合中的MoveTo、MovtToBottom、MoveToTop方法控制图层的次序。及MapLayer对象中的Visible属性控制某个图层显示与否。
//获取当前所打开的所有图层名及状态
procedure TLayerManagerFRM.FormActivate(Sender: TObject);
var
i: Integer;
CurrentLayer: ImoMapLayer;
begin
CheckListBoxLayers.Clear;
for i := 0 to https://www.360docs.net/doc/674034403.html,yers.Count - 1 do
begin
CurrentLayer := ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(i));
if https://www.360docs.net/doc/674034403.html,yerType = moMapLayer then
checkListBoxLayers.Items.Add(https://www.360docs.net/doc/674034403.html,);
CheckListBoxLayers.Checked[i] := CurrentLayer.Visible;
end;
end;
//确定各个按钮的状态
procedure TLayerManagerFRM.CheckListBoxLayersClick(Sender: TObject); var
CurrentLayer: Integer;
LayerCount: Integer;
Layer: ImoMapLayer;
begin
CurrentLayer := CheckListBoxLayers.ItemIndex;
Layer := ImoMapLayer(https://www.360docs.net/doc/674034403.html,yers.Item(CurrentLayer)); LayerCount := https://www.360docs.net/doc/674034403.html,yers.Count;
if (LayerCount = 1) or (LayerCount = 0) then
else
begin
sbTop.Enabled := CurrentLayer <> 0;
sbButtom.Enabled := CurrentLayer < LayerCount - 1;
sbUp.Enabled := CurrentLayer <> 0;
sbDown.Enabled := CurrentLayer < LayerCount - 1;
end;
CmbRemove.Enabled := CheckListboxLayers.Items.Count > 0; bbtnAttribute.Enabled := CmbRemove.Enabled;
end;
//移动图层
procedure TLayerManagerFRM.MoveLayer(Sender: TObject);
var
CurrentLayerIndex: Integer;
begin
CurrentLayerIndex := CheckListBoxLayers.ItemIndex;
if CurrentLayerIndex < 0 then
ShowMessage('请选择所要移动的图层。')
else
begin
with https://www.360docs.net/doc/674034403.html,yers do
begin
case (Sender as TSpeedButton).tag of
1:
MoveToTop(CurrentLayerIndex);
2:
MoveTo(CurrentLayerIndex, CurrentLayerIndex - 1);
3:
MoveTo(CurrentLayerIndex, CurrentLayerIndex + 1);
4:
MoveToBottom(CurrentLayerIndex);
end;
end;
end;
LayerManagerFRM.FormActivate(Sender);
CurrentMap.Refresh;
end;
Map控件
1)BeforeLayerDraw (index as Integer, hDC as stdole.OLEHandle)
绘制图层
2)AfterLayerDraw (index as Integer, canceled as Boolean, hDC as stdole.OLEHandle)
3)BeforeTrackingLayerDraw (hDC as stdole.OLEHandle)
绘制Tracking图层
4)AfterTrackingLayerDraw (hDC as stdole.OLEHandle)
BeforeLayerDraw事件:在绘制图层前执行,主要用于检查当前图层的显示比例,决定在当前显示比例下是否显示此图层。这样可使地图更具有地图学意义,同时提高显示速度。
第三章数据集