AE开发之地图浏览20210517
回顾
什么时候用什么对象
主要类:抽象类 组件类 普通类
抽象类无法new,普通类也无法new进行创建,只有是组件类才可以创建,创建的就是一个对象,定义变量的时候是类的名称,用类名去定义对象,前面都是用接口去定义,Imap去做Map,对象已经存在了,但是面前是面向接口编程,这时候暴露出啦的都是对象的接口,操作和使用通过接口去实现。
这样的话好处是:子类继承父类,同时继承接口,统一接口去实现在子类中实现,但是在工作空间工厂之类的操作时候,new的时候是不同的工作空间工厂。
组件类父类是普通类时候,只能new子类,然后用子类的接口去进行不同的操作,如工作空间的创立。
workspace是在OpenFromFile执行的时候,就去创建的了这个对象,暴露出来的接口是Iworkspace接口,有了这个接口,可以用他的属性方法去做操作,对其属性去访问,实际上是访问的该工作空间下的所有数据集,返回的是数据集的集合,排列,集合,后面是要做什么呢?
是让它回到最开始,然后利用next再次访问数据集,可能有很多不同的类,实际上在这个过程中也用到了许多的对象。我们虽然看不到,但是可以通过其接口进行操作。
new一个CAD workspacefactory
接口查询,可以看成类型的强制转换,但是有一个提示:强制转化的时候,要保证这个类存在这两个接口,不能由一个workspace接口强制到一个不存在的接口。
private void openCADToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "dwg file|*.dwg";//前面是一个提示,弹出的描述,后面是过滤
dlg.Multiselect = false;
dlg.Title = "Open dwg file";
//调用对话框
if (dlg.ShowDialog() == DialogResult.OK)
{
string pathfile = dlg.FileName;
int index = pathfile.LastIndexOf('\\');//找到最后一个斜杠的位置
string path = pathfile.Substring(0, index);//从0开始去取,一直取到最后一个
string name = pathfile.Substring(index + 1);
IWorkspaceFactory pWF = new ESRI.ArcGIS.DataSourcesFile.CadWorkspaceFactory();//利用工厂对象去生成一个CAD文件的工作空间
IWorkspace pW = pWF.OpenFromFile(path, 0); //打开对应的文件夹路径
// IFeatureWorkspace pFW = (IFeatureWorkspace)pW;
//IFeatureClass pFeatueClass =
ICadDrawingWorkspace pCadwrk = pW as ICadDrawingWorkspace;
ICadDrawingDataset pCadDraw = pCadwrk.OpenCadDrawingDataset(name);
ICadLayer pCadlayer = new CadLayerClass();
pCadlayer.CadDrawingDataset = pCadDraw;
//CadLayerClass pCadlayer= pCadwrk.OpenCadDrawingDataset(name);
ILayer player = new CadLayer();
ICadLayer pcadl = player as ICadLayer;
pcadl.CadDrawingDataset = pCadDraw;
axMapControl1.AddLayer(pcadl);//player prasterlayer都是指向同一个对象,但是这个地方需要一个ILayer接口
axMapControl1.Refresh();//刷新
}
加载fileGDB文件地理数据库(在personalgeodatabase基础上)
在personalGDB基础上,修改工作空间工厂和文件过滤器。
dlg.Filter = " File GDB|*.gdb";//前面是一个提示,弹出的描述,后面是过滤
IWorkspaceFactory pWorkFct = new FileGDBWorkspaceFactory();
大型数据库,arcSDE加载模式,创建一个SDE的workspacefactory
做地图浏览
1.创建后无内容,需要去加载,我们可以取一个地图的内容存过来。
pMapDoc.Save();//找到地图,把地图内容给取下来,取下来放到哪里去呢?
2.所以要用new的方法,但是创建后,现在还是空的,我们要把地图文档名称取下来。怎么取下来呢?
①查看是不是当前地图文档就有名称了,创建一个filename
string fileName = axMapControl1.DocumentFilename;
预示着,地图控件,有一个地图文档的文件名称,也就是磁盘下文档的存放路径。
如果有这个路径,就可以通过这个路径进行存储了
②如果地图文档名是空的,不用Openfiledialog,而是用savefiledialog,可以再去找到这个名称,再去存放
if(fileName==null)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "Map Document|*.mxd";
//可以添加tital等东西属性,课下查
if(dlg.ShowDialog()==DialogResult.OK)
{
fileName = dlg.FileName;
}
}
3.地图存放,存谁的内容呢?
应该是mapcontrol上面的这个地图,这个内容放在哪里呢?
先是要访问这个内容。
ReplaceContents
用于当前地图文档,用接口传进来的内容,替代当前显示的这个内容,这个contents代表一个对象一个内容,我们要把它更新进来,现在这个地图可以用axmapcontrol去访问这个地图,但我们要的不是map,而是一个Imxdcontents接口,需要去查map对象去查
map在carto类库里面。
可以通过强制转换得到IMxdDocument接口
if(fileName!=null)
{
IMap pMap = axMapControl1.Map;
IMxdContents mxdContents = (IMxdContents)pMap;
IMapDocument pMapDoc = new MapDocument();
//创建出对象,暴露出接口了
//pMapDoc.Save();//找到地图,把地图内容给取下来,取下来放到哪里去呢?
pMapDoc.ReplaceContents(mxdContents);
}
这时候,mapdocument对象当中就有这个接口了,我们的目的是存起来,实际上我们要判定一下。
new过程就是在磁盘下,制定位置创建文档,创建完后需要通过save方法,去存储。
pMapDoc.Save(true,true);
第一个参数:true相对路径,false是绝对路径
第二个true是指需要创建一个图标标识
尝试加入判断是否存在的代码(ppt)
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
string fileName = axMapControl1.DocumentFilename;//预示着,地图控件,有一个地图文档的文件名称,也就是磁盘下文档的存放路径。
if(fileName==null)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "Map Document|*.mxd";
//可以添加tital等东西属性,课下查
if(dlg.ShowDialog()==DialogResult.OK)
{
fileName = dlg.FileName;
}
}
if(fileName!=null)
{
IMap pMap = axMapControl1.Map;
IMxdContents mxdContents = (IMxdContents)pMap;
IMapDocument pMapDoc = new MapDocument();
//创建出对象,暴露出接口了
//pMapDoc.Save();//找到地图,把地图内容给取下来,取下来放到哪里去呢?
pMapDoc.New(fileName);
pMapDoc.ReplaceContents(mxdContents);
pMapDoc.Save(true,true);//true1相对路径,false是绝对路径,第二个true是指需要创建一个图标标识
}
}
如果进行代码调试,知道bug在哪里
断点设置
逐句调试
菜单栏上面有【调试】,可以设置为逐语句调试
结束调试
点击【继续】,或者逐句到最后
地图的放大缩小漫游
放大 zoom in
//先把地图缩小,再在地图上去显示,地图范围存到哪里去了呢
1.存地图范围,用什么去表达呢?
IEnvelope pEnv= axMapControl1.Extent;
2.调整地图范围,x y的比例和是否按比例去放大。
private void zoomInToolStripMenuItem_Click(object sender, EventArgs e)
{
//先把地图缩小,再在地图上去显示,地图范围存到哪里去了呢
IEnvelope pEnv= axMapControl1.Extent;
pEnv.Expand(0.5,0.5,true);//第一个参数是x,第二个参数是y,第三个参数是是否按比例
//放大两倍
axMapControl1.Extent = pEnv;
axMapControl1.Refresh();
}
查IEnvelop对象
https://blog.csdn.net/duck04551/article/details/6604338
IEnvelope是指地物的外接矩形,用来表示地物图形的大体位置和形状,一般可用于检索地物,判断地物间的拓扑关系,可以使得检索、判断的速度加快,因为有了IEnvelope,可以首先判断该外接矩形是否在检索范围内,而判断一个外接矩形是比较简单的。
Envelope也称包络线,是一个矩形区域,是每个几何形体的最小外接矩形。
每个Geometry都拥有一个Envelope,包括Envelope自身。IEnv是包络线对象的主要接口,定义了XMax、XMin、YMax、YMin、Height和Width等属性,用于获取或设置一个存在的包络线对象的空间坐标。
IEnvelope接口也提供了一些方法,如Expand、offset、CenterAt、PutCoords等。Expand方法用于按比例缩放包络线的范围,产生一个新的包络线对象;offset是一个偏移方法,通过一个给定的(X,y)移动包络线;CenterAt方法则通过改变包络线的中心点来移动包络线;PutCoords方法饿公国指定的坐标点来构造包络线。
接口的属性和方法:
IEnvelope接口的长宽属性Height和Width属性(读写,可以通过该属性获取或设置该边框的长和宽)
IEnvelope接口的4个顶点属性UpperLeft、UpperRight、LowerLeft和LowerRight(读写,返回IPoint类型的四个顶点,比直接获得最值坐标更加方便严谨)
IEnvelope接口的最值坐标属性XMax、XMin、YMax和YMin(读写,可以通过该属性获取或设置该边框的四个顶点的坐标)
IEnvelope接口的CenterAt(pPoint) (方法,将这个矩形的边框移动到参数pPoint的位置,但是其他属性不变,如它的Width和Height)
IEnvelope接口的Union (inEnvelope ) (方法,将参数输入的几何边框和调用该方法的几何边框求并集,并将结果赋值给第一个边框,即调用此方法的object)
IEnvelope接口的Intersect (inEnvelope ) (方法,返回与输入参数相交的区域的几何边框,并将结果赋值给第一个边框,即调用此方法的object)
IEnvelope接口的PutCoords (XMin, YMin,XMax,YMax) (方法,将新建的一个边框的4个极坐标设置为输入的参数)
IEnvelope接口的QueryCoords (XMin, YMin,XMax,YMax)(方法,将已有的一个边框的4个极坐标输出到参数当中以备后用)
IEnvelope接口的Expand (dx, dy, asRatio) (方法,按照输入的dx与dy参数来放大或者缩小当前的边框,用与对ArcMap窗体的中心放大或缩小,或者点击屏幕获得点击点的坐标,并将中心点设置成点击点,并进行一定比例的放大或者缩小)
IEnvelope接口的Offset (X, Y) (方法,将已有的一个边框的按照输入参数的大小来进行水平竖直的移动)
geometry类库(几何类库)
https://blog.csdn.net/BIT_SKY/article/details/50056605
一、Geometry类的层次
几何类定义了下述层次:
· Geometry(非实例化)
· Point(可实例化的)
· Curve(非实例化)
· LineString(可实例化的)
· Line
· LinearRing
· Surface(非实例化)
· Polygon(可实例化的)
· GeometryCollection(可实例化的)
· MultiPoint(可实例化的)
· MultiCurve(非实例化)
· MultiLineString(可实例化的)
· MultiSurface(非实例化)
· MultiPolygon(可实例化的)
不能在非实例化类中创建对象。能够在可实例化类中创建对象。所有类均有属性,可实例化类还可以包含声明(定义有效类实例的规则)。
Geometry是一种基本类。它是一种抽象类。Geometry的可实例化子类限制为可在2维坐标空间中存在的0、1、2维几何对象。所有的可实例化几何类是这样定义的,从而使得几何类的实例从拓扑意义上讲是闭合的(也就是说,所有定义的几何类包含其边界)。
基本Geometry类具有关于Point、Curve、Surface和GeometryCollection的子类:
· Point表示0维对象。
· Curve表示1维对象,具有子类LineString,以及次级子类Line和LinearRing。
· Surface是为2维对象设计的,具有子类Polygon。
· GeometryCollection具有特殊的0维、1维和2维类集合,名为MultiPoint、MultiLineString和MultiPolygon,分别用于为对应的Points、LineStrings和Polygons集合进行几何建模。MultiCurve和MultiSurface是作为抽象超类引入的,它们归纳了用于处理Curves和Surfaces的集合接口。
Geometry、Curve、Surface、MultiCurve和MultiSurface定义为非实例化类。它们为其子类定义了公用方法集合,而且是为扩展而包含在内的。
Point、LineString、Polygon、GeometryCollection、MultiPoint、MultiLineString和MultiPolygon定义为可实例化类。
二、类Geometry
Geometry是层次结构的根类。它是一种非实例化类,但具有很多属性,这些属性对由任何Geometry子类创建的所有几何值来说是共同的。下面介绍了这些属性(尤其是具有自己特殊属性的子类)。
Geometry属性
Geometry值具有下述属性:
· 其type(类型)。每个geometry属于层次结构中可实例化类之一。
· 其SRID,或空间参考ID。该值确定了用于描述定义几何对象的坐标空间的空间坐标系统。
在MySQL中,SRID值仅是与geometry值相关的整数值。所有计算均是在欧几里得几何系(平面)中进行的。
· 它在其空间坐标系统中的coordinates(坐标),表示为双精度数值(8字节)。所有的非空几何对象至少包含一对坐标(X、Y)。空几何对象不含坐标。
坐标与SRID相关。例如,在不同的坐标系内,两个对象之间的距离会有所不同,即使这两个对象具有相同的坐标也同样。这是因为,平面坐标系中的距离和地心坐标系(地球表面上的坐标)中的距离是不同的事项。
· 其interior(内部)、boundary(边界)和exterior(外部)。
每个几何对象均占据空间中的某一位置。几何对象的exterior(外部)指的是未被该对象占据的所有空间。其interior(内部)指的是被该对象占据的空间。其boundary(边界)指的是几何对象内部和外部之间的界面。
· 其MBR(最小边界矩形)或包络面。这是一种边界几何值,由最小和最大坐标(X,Y)构成。
· ((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
· 无论值是简单的或非简单的。类型(LineString、MultiPoint、MultiLineString)的几何值或是简单的,或是非简单的。每个类型决定了其自己的简单或非简单声明。
· 无论值是封闭的或非封闭的。类型(LineString、MultiPoint)的几何值或是封闭的,或是非封闭的。每个类型决定了其自己的封闭或非封闭声明。
· 无论值是空的或非空的。如果没有任何点,几何对象是空的。空几何对象的内部、外部和边界未定义(也就是说,它们由Null值表示)。空的几何对象定义为总是简单的,面积为0。
· 其dimension(维数)。几何对象的维数为−1、0、1或2:
o −1用于空几何对象。
o 0用于无长度、无面积的几何对象。
o 1用于具有非0长度和0面积的几何对象。
o 2用于具有非0面积的几何对象。
Point对象的维数为0。LineString对象的维数为1。Polygon对象的维数为2。MultiPoint、MultiLineString和MultiPolygon对象的维数与构成它们的元素的维数相同。
三、类Point
Point(点)指的是代表坐标空间中单个位置的几何类。
Point示例
· 想像一张具有众多城市的大世界地图。每个Point对象可代表1个城市。
· 在城市地图上,Point对象可代表1个公共汽车站。
Point属性
· X-坐标值。
· Y-坐标值。
· Point定义为0维几何对象。
· Point的边界为空集合。
缩小 zoom out
private void zoomOutToolStripMenuItem_Click(object sender, EventArgs e)
{
IEnvelope pEnv = axMapControl1.Extent;
pEnv.Expand(1.5, 1.5, true);//第一个参数是x,第二个参数是y,第三个参数是是否按比例
axMapControl1.Extent = pEnv;
axMapControl1.Refresh();
}
drag zoom in 显示拉框范围,实现拉框放大
1.在地图控件中拉框,拉框会激发MouseDown等事件,拉框就在这些事件中操作
2.在mapControl双击,就会自动跳转到axMapControl1_OnMouseDown事件
3.怎么去拉框呢?
axMapControl1.TrackRectangle();
4.怎么去接收拉框的范围呢?
IEnvelope pEnv = axMapControl1.TrackRectangle();
5、如果点击,却没有拉框,或者拉出的是一个直线,则返回对象为空。需要去判断。
if(pEnv==null||pEnv.IsEmpty||pEnv.Width==0)
//IsEmpty返回是否非空,是个属性。
//如果高度为0,可能拉出的是一条直线,同理宽度为0
{
return;
}
6.把拉框范围赋给地图控件
7.刷新
8、设置属性或者字段,判断拉框是为了放大还是缩小,由于不需要外部访问,所以设置为属性即可。
namespace MapControl2
{
public partial class Form1 : Form
{
private string toolAction;
}
}
9.在MouseDown事件中进行判断,可以用分支语句switch进行判断。
switch (toolAction)
{
case "Drag zoom in"://对大小写敏感,可以直接复制,减少出错
IEnvelope pEnv = axMapControl1.TrackRectangle();
if (pEnv == null || pEnv.IsEmpty || pEnv.Width == 0)
//IsEmpty返回是否非空,是个属性。
//如果高度为0,可能拉出的是一条直线,同理宽度为0
{
return;
}
axMapControl1.Extent = pEnv;
axMapControl1.Refresh();
break;
case "grag zoom out":
IEnvelope pEnv = axMapControl1.TrackRectangle();
break;
case "pan":
IEnvelope pEnv = axMapControl1.TrackRectangle();
break;
}
值得注意的是:
①对大小写敏感
case "Drag zoom in"://对大小写敏感,可以直接复制,减少出错
②形式:
case ... :
break;
10.放大缩小倍数的确定,可以用拉框的宽和高,和已知图框的宽高进行比值,得到新地图的范围。
先创一个范围。
case "grag zoom out":
IEnvelope pEnv = axMapControl1.TrackRectangle();
if (pEnv == null || pEnv.IsEmpty || pEnv.Width == 0)
//IsEmpty返回是否非空,是个属性。
//如果高度为0,可能拉出的是一条直线,同理宽度为0
{
return;
}
double x_scal = axMapControl1.Extent.Width / pEnv.Width;
double y_scal = axMapControl1.Extent.Height / pEnv.Height;
11.算新窗口的高度和宽度。
double width = axMapControl1.Extent.Width * x_scal;
double higth = axMapControl1.Extent.Height * y_scal;
12.找新窗口的x y 的最小值。
double x_min = pEnv.XMin-(pEnv.XMin- axMapControl1.Extent.XMin)*x_scal;
double y_min = pEnv.YMin -(pEnv.YMin - axMapControl1.Extent.YMin) * y_scal;
13.找新窗口X Y的最大值
在这里插入代码片
14.重设置工作范围
pEnv.PutCoords(x_min, y_min, x_max, y_max);
显示整个地图范围
private void fullMapToolStripMenuItem_Click(object sender, EventArgs e)
{
axMapControl1.Extent = axMapControl1.FullExtent;
axMapControl1.Refresh();
}
漫游 PAN
case "pan":
axMapControl1.Pan();
axMapControl1.Refresh();
记忆视窗范围。(如快速回到上一个视窗范围)
1.谁去记忆,放到哪里去呢?
(范围的堆栈,在哪里呢?)
IExtentStack pStack= axMapControl1.ActiveView.ExtentStack;//视窗范围的堆栈
2.判断是返回前视窗还是后视窗。
private void formMapToolStripMenuItem_Click(object sender, EventArgs e)
{
IExtentStack pStack= axMapControl1.ActiveView.ExtentStack;//视窗范围的堆栈
if(pStack.CanRedo())
{
pStack.Undo();//回到前视窗
axMapControl1.Refresh();
}
}
private void backMapToolStripMenuItem_Click(object sender, EventArgs e)
{
IExtentStack pStack = axMapControl1.ActiveView.ExtentStack;//视窗范围的堆栈
if (pStack.CanRedo())
{
pStack.Redo();//回到后视窗
axMapControl1.Refresh();
}
}
查ExtentStack
https://blog.csdn.net/mazhiyuan1981/article/details/110494541
https://blog.csdn.net/chh19941125/article/details/89211342
http://zhihu.geoscene.cn/question/12013
堆栈(Stack)代表了一个后进先出的对象集合。
当您需要对各项进行后进先出的访问时,则使用堆栈。
当您在列表中添加一项,称为推入元素,也叫压栈,当您从列表中移除一项时,称为弹出元素,也叫出栈。
【问题分析】:
Reset之后IExtentStack.Count变成0,而只有当IExtentStack.Count变成2时才能执行Undo操作,因此需要两次平移操作才能将其增长成2。
解释:Count代表了堆栈中的记录数量,Undo操作必须要在堆栈数量大于等于2时才能执行,因为回退后还是需要显示一个状态的,不可能显示成null。
而Reset函数将堆栈清空,因此此时需要连续执行两次压栈才能再执行出栈。
【解决办法】:
在执行Reset后紧接着执行一次pExtStack.Do方法即可。
感兴趣区 “书签”
1.在解决方案里面添加窗体应用
注意命名特点:
upIM窗体
2.添加label,添加textbox,添加button
3.标签存在哪里?什么时间去进行标签的存放?
点击OK的时候进行存放。
标签名称在textBox当中。
所以要在button1进行操作。
访问控件的active,涉及到窗口的关联,传过来之前的窗口,需要定义一个属性。
在最初窗口添加一个菜单项,去调用新的窗口
4、
private void addBookmarkToolStripMenuItem_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.PMapView = axMapControl1.Map;
frm.ShowDialog();
}
IAOIBookmark标签对象
https://blog.csdn.net/hyman_c/article/details/53102013
location属性,记忆当前视图窗口的位置,要存放到这里去,name是标签名称。
这两个属性,大家要适用。
常见问题
引用需要using,仅仅添加引用是对整个项目的应用。
11