资源描述
1、AE开发技术文档
一、数据加载问题
1、加载个人数据库
个人数据库是保存在Access中的数据库。加载方式有两种:通过名字和通过属性加载(也许不只是这两种,AE中实现同一功能可以有多种方式)
A、通过设置属性加载个人数据库
首先通过IPropertySet接口 定义要连接数据库的一些相关属性,在个人数据库中为数据库的路径,例如:
IPropertySet Propset= new PropertySetClass();
Propset.SetProperty(“DATABASE”,@”D:\test\Ao\data\sh\Mapdata.mdb”);
当定义完属性并设置属性后就可以进行打开数据库的操作了,在ArcEngine开发中存在IWorkspaceFactory 、IFeatureWorkspace 、IFeatureClass 、IFeatureLayer等几个常用的用于打开和操作数据空间地物的接口。IWorkspaceFactory 是一个用于创建和打开工作空间的接口,它是一个抽象的接口,我们在具体应用时要用对应的工作空间实例化它,如下:
IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass (); 如果我们打开的是SDE 数据库就要用 SdeWorkspaceFactoryClass 实例化Fact。当我们完成了工作空间的实例化后就可以根据上边设置的属性打开对应的Access 数据库了。打开方式如下:
IFeatureWorkspace Workspace = Fact.Open( Propset,0) as IFeatureWorkspace;
打开Access 工作空间后接下来的事情是做什么了,很简单,找到对应的地物类,赋给相应的层,通过MapControl 控件添加对应的层,然后刷新地图。以下为添加某一层的代码:
IFeatureClass Fcls = Workspace.OpenFeatureClass("District");//找到对应的地物类
IFeatureLayer Fly = new FeatureLayerClass();//建立新图层
Fly.FeatureClass = Fcls; //将地物赋给相应的层
MapCtr.Map.AddLayer (Fly);//添加层
MapCtr.ActiveView.Refresh();//刷新地图
其中District 为地物类的名字,MapCtr 为AE中MapControl 的对象。上边的通过属性设置加载数据空间的方式还可以用于SDE 数据库,在SDE 数据库加载时会介绍。
以下为通过设置属性加载Access 数据库的完整C#代码:
public void AddAccessDBByPro()
{
IPropertySet Propset = new PropertySetClass();
Propset.SetProperty("DATABASE",@"D:\test\Ao\data\sh\MapData.mdb" );
IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass ();
IFeatureWorkspace Workspace = Fact.Open(Propset,0) as IFeatureWorkspace;
IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");
IFeatureLayer Fly = new FeatureLayerClass();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer(Fly);
MapCtr.ActiveView.Refresh();
}
B、通过数据库名字加载个人数据库
public void AddAccessDBByName()
{
IworkspaceName pWorkspaceName = new WorkspaceNameClass();
pWorkspaceName.WorkspaceFactoryProgID= “esriDataSourcesGDB.AccessWorkspaceFactory”;
pWorkspaceName.PathName =@“D:\test\Ao\data\sh\MapData.mdb”;
IName n=pWorkspaceName as IName;
IFeatureWorkspace Workspace= n.Open() as IFeatureWorkspace;
IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");
IFeatureLayer Fly = new FeatureLayerClass();
Fly.FeatureClass = Fcls;
MapCtr.Map.AddLayer(Fly);
MapCtr.ActiveView.Refresh();
}
首先创建一个个人数据库工作空间名,再指定工作空间名的ProgID,以确定打开的是什么类型的工作空间,例如在打开Access个人数据库时,使用下面代码;
IworkspaceName pWorkspaceName = new WorkspaceNameClass();
pWorkspaceName.WorkspaceFactoryProgID= “esriDataSourcesGDB.AccessWorkspaceFactory”;
pWorkspaceName.PathName =@“D:\test\Ao\data\sh\MapData.mdb”;
属性WorkspaceFactoryProgID可以确保工作空间是AccessWorkspaceFactory,即个人数据库,同时要指定打开数据库路径。为了打开数据库,打开工作空间必须使用IName接口(思考有没有其他办法),,所以接着定义IName、对象,并把工作空间名转换成IName类型,并赋值给IName对象,然后通过IName对象的open方法打开相应的工作空间,代码如下:
IName n=pWorkspaceName as IName;
IFeatureWorkspace Workspace= n.Open() as IFeatureWorkspace;
2、AE开发编辑功能
数据编辑问题
1. 需要了解的概念
长事务 短事务 编辑空间 抽象类,类,和组件对象类
2、最基本的添加点线面功能
添加点(方法有多种,基本思路一样,只是少量的接口有变化)
通过FeatureClass的CreatFeature函数来添加地物。
public void AddPointByStore()
{
//得到要添加地物的图层
IFeatureLayer l=MapCtr.Map.get_Layer(0) as IFeatureLayer;
//定义一个地物类,把要编辑的图层转化为定义的地物类
IFeatureClass fc= l.FeatureClass;
//先定义一个编辑的工作空间,然后把它转化为数据集,最后转化为编辑工作空间,
IWorkspaceEdit w=(fc as IDataset).Workspace as IWorkspaceEdit;
IFeature f;
IPoint p;
//开始事务操作
w.StartEditing(false); //////????????????????????????
//开始编辑
w.StartEditOperation();
for(int i=0;i<100;i++)
{
//创建一个地物
f=fc.CreateFeature();
p=new PointClass();
//设置点的坐标
p.PutCoord(i,i);
//确定图形类型
f.Shape=p;
//保存地物
f.Store()
}
//结束编辑
w.StopEditOperation();
//结束事务操作
w.StopEditing(true);
}
二、添加线
方法跟添加点一样,不同的只是地物类型不一样而已,
AE中各类库的介绍
1、 问题一:什么是UI组件?
2、 类库介绍
空间拓扑运算
1、高级几何对象:点(point)、多点(multipoint)、线(polyline)、面(polygon)、multipatch等。(multipatch:多片,三维地形图中的地图符号包括点状符号、线状符号、面状符号、体状符号以及多片(MultiPatch)符号等)
2、拓扑:空间拓扑描述的事自然界地理对象的空间位置关系,即相邻、重合、连通等。是在同一个要素集下的要素类之间的关系的集合,所以要参与一个拓扑的所有要素类,必须在同一个要素集内(也就是具有同一个空间参考),这样进行的拓扑检查才是精确的。
3、一个要素集可以有多个拓扑,但每个要素类最多只能参与一个拓扑,一个拓扑中可以定义多个规则,是地理对象空间属性的一部分,在目前ESRI提供的数据存储方式中,Coverage和GeoDatabase能够建立拓扑,而Shape格式的数据不能建立拓扑。
4、 esriTRTAny———— 任何拓扑规则,查询拓扑的时候用(ESRI提供的拓扑关系)
5、AE中提供了ITopologicalOperator接口用于拓扑运算,ITopologicalOperator接口用来通过对已存在的几何对象做空间拓扑运算,以产生新的集合对象。ITopologicalOperator接口在GIS开发中的使用非常广泛,通常GIS系统中的缓冲区分析、裁剪几何图形、几何图形差分操作、几何图形合并操作等都需要此接口。
Boundary 方法用于几何图形对象的边界。Polygon的几何对象的Boundary是组成它的Polyline几何对象,Polyline几何对象的Boundary是组成它的顶点Point几何对象,而Point的几何对象的Boundary是空对象。
Buffer 用于集合对象缓冲区分析拓扑操作,该方法用于给一个高级几何对象产生一个缓冲区,无论是Polygon、Polyline、还是Point,他们的缓冲区都是具有面积的几何对象。
Clip 用于对几何对象进行裁剪空间拓扑操作。Clip方法可用一个Envelope对象对一个几何对象进行裁剪,结果是几何对象被Envelope对象所包围的部分。
ConstructUion用于将多个枚举对象与单个几何对象合并为单个几何对象。
ConvexHull 用于构建几何对象的凸多边形。ConvexHull方法用于产生一个几何图形的最小的边框凸多边形(没有凹面包含几何图形的最小多边形)
Cut 用于切割几何对象,不支持GeometryBags几何对象,它可以指定一条切割曲线和一个几何图形,经过切割运算后把几何图形分为左右两部分,左右两部分是相对曲线的方向而言的。点与多点不可被分割。Polyline和Polygon只有与切割曲线相交时才能执行Cut方法。
Difference 用于从一个几何图形中减去其与另一个图形相交的部分,产生两个几何对象的差集。
Intersection方法用于两个同纬度几何对象的交集部分。
Simplify用于使几何对象拓扑一致。
SymmetricDifference对称差分可将两个几何图形的并集部分减去两个几何图形交集的部分。
开发实例
一、 鹰眼功能的实现:
分析:鹰眼图的操作主要由以下几个动作,当在一个控件中移动一幅图的时候另一控件中的图也发生变化,当在主控件中重新加载一幅图的时候,另外一个控件的图也发生相应的变化,同时我们在鸟瞰的控件中加入一红色边框,注意这个其实是一个面,只是填充的颜色是透明的而已。通过分析我们知道,我们要添加两个MapControl控件,名字分别是axMapControl1和axMapControl2,其中axMapControl1为主图,而axMapControl2为鸟瞰图。
方法:步骤一:对于名称为axMapControl1的MapControl控件,只需要在axMapControl1的OnExtentUpdated和OnMapReplaced中分别添加以下代码:
private void axMapControl1_OnExtentUpdated(object sender, IMapControlEvents2_OnExtentUpdatedEvent e)
{
// 得到新范围
IEnvelope pEnvelope = (IEnvelope)e.newEnvelope;
IGraphicsContainer pGraphicsContainer = axMapControl2.Map as IGraphicsContainer;
IActiveView pActiveView = pGraphicsContainer as IActiveView;
//在绘制前,清除axMapControl2中的任何图形元素
pGraphicsContainer.DeleteAllElements();
IRectangleElement pRectangleEle = new RectangleElementClass();
IElement pElement = pRectangleEle as IElement;
pElement.Geometry = pEnvelope;
//设置鹰眼图中的红线框
IRgbColor pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 255;
//产生一个线符号对象
ILineSymbol pOutline = new SimpleLineSymbolClass();
pOutline.Width = 3;
的属性
IFillSymbol pFillSymbol = new SimpleFillSymbolClass();
pFillSymbol.Color = pColor;
pFillSymbol.Outline = pOutline;
IFillShapeElement pFillShapeEle = pElement as IFillShapeElement;
pFillShapeEle.Symbol = pFillSymbol;
pGraphicsContainer.AddElement((IElement)pFillShapeEle, 0);
pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
if (axMapControl1.LayerCount > 0)
{
axMapControl2.Map = new MapClass();
for (int i = 0; i <= axMapControl1.Map.LayerCount - 1; i++)
{
axMapControl2.AddLayer(axMapControl1.get_Layer(i));
}
axMapControl2.Extent = axMapControl1.Extent;
axMapControl2.Refresh();
}
}
步骤二:对于名称为axMapControl2的MapControl控件,只需要在axMapControl2的OnMouseMove和OnMouseDown中分别添加以下代码:
private void axMapControl2_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
{
if (e.button == 1)
{
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
axMapControl1.CenterAt(pPoint);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
}
private void axMapControl2_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
if (axMapControl2.Map.LayerCount > 0)
{
if (e.button == 1)
{
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
axMapControl1.CenterAt(pPoint);
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
else if (e.button == 2)
{
IEnvelope pEnv = axMapControl2.TrackRectangle();
axMapControl1.Extent = pEnv;
axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
}
}
二、 显示属性表的信息
我们知道ArcMap中的Table of Contents有很多功能,如下图:
而ArcGIS Engine提供的TOCControl控件几乎没有提供,那么这些都是需要自己开发的,在这里我做一个显示属性表的功能。
分析:要显示某一个图层的属性表,首先要将这个图层选中,然后在另外一个Form中将选中的这个图层的属性信息进行显示。
方法:添加一个上下文菜单,添加一个新的Form窗体,在这个新的窗体上添加GridView控件,并在TOCControl控件的OnMouseDown事件下添加如下代码(pGlobalFeatureLayer是我定义的一个全局变量):
private void axTOCControl1_OnMouseDown(object sender, ESRI.ArcGIS.Controls.ITOCControlEvents_OnMouseDownEvent e)
{
if (axMapControl1.LayerCount > 0)
{
esriTOCControlItem pItem = new esriTOCControlItem();
pGlobalFeatureLayer = new FeatureLayerClass();
IBasicMap pBasicMap = new MapClass();
object pOther = new object();
object pIndex = new object();
axTOCControl1.HitTest(e.x, e.y, ref pItem, ref pBasicMap, ref pGlobalFeatureLayer, ref pOther, ref pIndex);
}
if (e.button == 2)
{
context.Show(axTOCControl1, e.x, e.y);
}
}
在上下文菜单的打开属性表的Click事件中添加如下代码:
private void 打开属性表ToolStripMenuItem_Click(object sender, EventArgs e)
{
FormTable Ft = new FormTable(pGlobalFeatureLayer as IFeatureLayer);
Ft.Show();
}
在新的窗体中添加一个将属性表显示到GridView控件中的函数,如下:
public void Itable2Dtable()
{
IFields pFields;
pFields = pFeatureLayer.FeatureClass.Fields;
dtGridView.ColumnCount = pFields.FieldCount;
for (int i = 0; i < pFields.FieldCount;i++ )
{
string fldName = pFields.get_Field(i).Name;
dtGridView.Columns[i].Name = fldName;
dtGridView.Columns[i].ValueType = System.Type.GetType(ParseFieldType(pFields.get_Field(i).Type));
}
IFeatureCursor pFeatureCursor;
pFeatureCursor = pFeatureLayer.FeatureClass.Search(null, false);
IFeature pFeature;
pFeature = pFeatureCursor.NextFeature();
while (pFeature != null)
{
string[] fldValue = new string[pFields.FieldCount];
for (int i = 0; i < pFields.FieldCount; i++)
{
string fldName;
fldName = pFields.get_Field(i).Name;
if (fldName==pFeatureLayer .FeatureClass .ShapeFieldName)
{
fldValue[i] = Convert.ToString(pFeature.Shape.GeometryType);
}
else
fldValue[i] = Convert.ToString(pFeature.get_Value(i));
}
dtGridView.Rows.Add(fldValue);
pFeature = pFeatureCursor.NextFeature();
}
}
数据库知识:
DB2、Informix、PostgreSQL
数据库打开方式以及方法:
1、 打开个人数据库:
public IWorkspace GetMDBWorkspace(String _pGDBName)
{
IWorkspaceFactory pWsFac = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsFac.OpenFromFile(_pGDBName,0);
return pWs;
}
2、 打开文件数据库:
public IWorkspace GetFGDBWorkspace(String _pGDBName)
{
IWorkspaceFactory pWsFac = new FileGDBWorkspaceFactoryClass();
IWorkspace pWs = pWsFac.OpenFromFile(_pGDBName, 0);
return pWs;
}
3、 打开SDE数据库:
打开SDE数据库我们使用的是Open方法,要用这个方法,我们就要对IPropertySet对象设置,要打开SDE数据库,我们要获取SDE数据库的服务器地址,数据库实例,数据库,用户,密码等参数。而IPropertySet就好比一个Key-Value的对象,用来帮组我们设置这些,然后传到Open方法中。
public IWorkspace GetSDEWorkspace(String _pServerIP, String _pInstance, String _pUser, String _pPassword, String _pDatabase, String _pVersion)
{
ESRI.ArcGIS.esriSystem.IPropertySet pPropertySet = new ESRI.ArcGIS.esriSystem.PropertySetClass();
pPropertySet.SetProperty("SERVER", _pServerIP);
pPropertySet.SetProperty("INSTANCE", _pInstance);
pPropertySet.SetProperty("DATABASE", _pDatabase);
pPropertySet.SetProperty("USER", _pUser);
pPropertySet.SetProperty("PASSWORD", _pPassword);
pPropertySet.SetProperty("VERSION", _pVersion);
ESRI.ArcGIS.Geodatabase.IWorkspaceFactory2 workspaceFactory;
workspaceFactory = (ESRI.ArcGIS.Geodatabase.IWorkspaceFactory2)new ESRI.ArcGIS.DataSourcesGDB.SdeWorkspaceFactoryClass();
return workspaceFactory.Open(pPropertySet, 0);
}
注意,打开SDE数据库需要用到ArcGIS Engine运行时的企业级许可。(即此时的License需要特别设置——ArcEngine的Lisence应使用企业数据库类型,在From1_Load事件中初始化lisence,不能使用lisence控件设置,否则提示没有许可lisence。)
具体的解决代码如下:
private void From1_Load(object sender,EventArg e)
{
IAoInitialize pao=new AoInitializeClass();
pao.Initialize(esriLisenceProductCode.esriLisenceProductCodeEngineGeoDB);
}
4.4.2 获取数据库中的要素类
在ArcGIS Engine中,要得到某一个类,首要要获取工作空间,然后进入工作空间再得到相应的东西,也就是以下两个步骤:
l 获取工作空间;
l 获取相应的要素类。
我们定义一个函数用来获取个人数据库的路径
public string WsPath()
{
string WsFileName="";
OpenFileDialog OpenFile = new OpenFileDialog();
OpenFile.Filter = "个人数据库(MDB)|*.mdb";
DialogResult DialogR = OpenFile.ShowDialog();
if (DialogR == DialogResult.Cancel)
{
}
else
{
WsFileName = OpenFile.FileName;
}
return WsFileName;
}
要获取要素类,首先获取工作空间,然后对工作空间中的要素类进行遍历,代码如下:
private void button2_Click(object sender, EventArgs e)
{
string WsName = WsPath();
if (WsName != "")
{
IWorkspaceFactory pWsFt = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsFt.OpenFromFile(WsName, 0);
IEnumDataset pEDataset =pWs.get_Datasets(esriDatasetType.esriDTAny);
IDataset pDataset = pEDataset.Next();
while (pDataset != null)
{
if (pDataset.Type ==esriDatasetType.esriDTFeatureClass)
{
FeatureClassBox.Items.Add(pDataset.Name);
}
//如果是数据集
else if (pDataset.Type == esriDatasetType.esriDTFeatureDataset)
{
IEnumDataset pESubDataset = pDataset.Subsets;
IDataset pSubDataset = pESubDataset.Next();
while (pSubDataset != null)
{
FeatureClassBox.Items.Add(pSubDataset.Name);// ----这是从哪里来的???------------
pSubDataset = pESubDataset.Next();
}
}
pDataset = pEDataset.Next();
}
}
FeatureClassBox.Text = FeatureClassBox.Items[0].ToString();
}
判断要素是否被编辑:
ArcGIS Engine 提供了一个IDatasetEdit的接口用来判断我们的数据是否处于编辑状态,该接口只有一个方法,如下:
示例代码如下:
public bool ISEdit (IFeatureClass pFeatureClass)
{
IDatasetEdit pDataEdit = pFeatureClass as IDatasetEdit;
return pDataEdit.IsBeingEdited();
}
如何删除要素类:
IFeatureWorkspace这个接口主要是用于管理基于矢量数据的,如表,要素类,要素数据集等。
要想删除一个要素类,那么必须先得到这个。,如要打开一个名称为PointTest的要素类,只需要在OpenFeatureClass中传入这个要素类的名称,代码如下:
IWorkspaceFactory pWsFt = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsFt.OpenFromFile(WsName, 0);
IFeatureWorkspace pFWs = pWs as IFeatureWorkspace;
IFeatureClass pFClass = pFWs.OpenFeatureClass("PointTest");
如果是在ArcMap中,我们会切换到Catalog中然后进入相应的数据库,然后删除相应的要素类,这种操作会让我们想到FeatureClas这个对象会提供删除的方法,其实不然,这个删除的方法是定义在Dataset这个对象中。
private void button1_Click(object sender, EventArgs e)
{
string WsName = WsPath();
if( WsName !="")
{
IWorkspaceFactory pWsFt = new AccessWorkspaceFactoryClass();
IWorkspace pWs = pWsFt.OpenFromFile(WsName, 0);
IFeatureWorkspace pFWs = pWs as IFeatureWorkspace;
IFeatureClass pFClass = pFWs.OpenFeatureClass("PointTest");
IDataset pDatset = pFClass as IDataset;
pDatset.Delete();
}
}
删除前:
删除后:
创建要素类
创建要素类用到了IFeatureWorkspace.CreateFeatureClass方法。
所需接口:IField,IFieldEdit,IFields,IFieldsEdit,IGeometryDef,IGeometryDefEdit接口
(注意 在NET中,会遇到以“_2”结尾的属性,这些属性是可写的。)
//定义一个几何字段,类型为点类型
ISpatialReference pSpatialReference = axMapControl1.ActiveView.FocusMap.SpatialReference;
IGeometryDefEdit pGeoDef = new GeometryDefClass();
IGeometryDefEdit pGeoDefEdit = pGeoDef as IGeometryDefEdit;
pGeoDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;
pGeoDefEdit.SpatialReference_2 = pSpatialReference;
//定义
展开阅读全文