绘制街道时,我们会对LRDL、VEGA、RESA、RESL和RESP中的要素进行操作,编辑完成后,改动的要素涉及多个图层,一旦出错,回撤功能将变得十分重要;同时,截取裁切LRDL面会产生许多复合要素(multipart feature),要求是不能产生复合要素。本文针对这两个问题,进行分析和探讨。
1 支持撤销操作
1.1 方法接口介绍
arcengine中使用StartOperation 和StopOperation,将编辑操作记录到ArcGIS引擎中
每一个开始结束对之间的操作会被存储在一个操作栈中,点击undo时,会以整个操作栈的形式,执行撤销操作
不能保存编辑或者停止编辑,否则会出错;
在StopOperation之后,不能再在同一函数或按钮中,对刚才操作栈进行修改,否则调试不会出错;运行会崩
1.1.1 StartOperation()
[C#]public void StartOperation ();
Description
StartOperation marks the beginning of an edit operation. To provide undo/redo capability programmatically all edits must be performed within an edit operation. (标记编辑操作的开始,提供了以编程方式记录编辑操作中执行的所有编辑)
Calling IEngineEditor::StopOperation completes an edit operation which is then added to the top of the operation stack. The operation stack is how ArcGIS Engine implements Undo and Redo. When using StartOperation, proper error handling, including the use of IEgineEditor::AbortOperation, is neccessary.(调用StopOperation完成编辑操作,然后将其添加到操作堆栈的顶部。操作堆栈是ArcGIS引擎如何实现撤消和重做的。使用StartOperation时,必须进行正确的错误处理,包括使用IEEngineEditor:AbortOperation)
Edit operations cannot be nested; calling StartOperation within another operation will raise an error.(不能嵌套编辑操作,在另一个操作中调用StartOperation将引发错误)
Remarks
This method fires the IEngineEditEvents::OnStartOperation event.
(该方法将触发OnStartOperation事件)
1.1.2 StopOperation
1. [C#]public void StopOperation ( 2. stringoperationName);
Description
StopOperation marks the end of an edit operation. Calling StopOperation creates an edit operation that is added to the top of the operation stack. The operation stack is how ArcGIS Engine implements Undo and Redo.(StopOperation标记编辑操作的结束,调用该方法将在操作栈的顶部创建一个编辑操作,这也是ArcGIS引擎实现撤销和重做的操作栈)
When using IEngineEditor::StartOperation proper handling of errors, including the use of IEngineEditor::AbortOperation, is neccessary.(使用StartOperation 时,必须进行正确的错误处理,包括使用IEEngineEditor:AbortOperation)
The string argument allows the operation to be identified on the operaton stack.(不能嵌套编辑操作,在另一个操作中调用StartOperation将引发错误)
Remarks
This method fires the IEngineEditEvents::OnBeforeStopOperation and IEngineEditEvents::OnStopOperation events.
该方法将触发OnBeforeStopOperation 和OnStopOperation 事件
1.2 代码实现
public void supportUndo() { UID editorUID= new UIDClass(); editorUID.Value = "esriEditor.Editor"; IMxApplication mxApplication = new ArcMap.ThisApplication; IApplication application = mxApplication as IApplication; IEidtor pEditor = application.FindExtensionByCLSID(editorID) as IEidtor; IEditorLayers pEditorLayer = pEditor as IEditorLayers; if(pEditor.EditState != esriEditState.esriStateEditing) { MessageBox("先打开编辑器"); return; } IActiveView pActiveView = ArcMap.Document.FocusMap as IActiveView; pEditor.StartOperation(); //------------------------------------------------------- // 绘制街区,标记删除点房,道路GB修改等操作 //------------------------------------------------------- pEditor.StopOperation("Edit Finshed"); }
2 炸开复合要素(explode multipart feature)
关于这个问题,网上大多是ArcEngine判断要素(feature)是否为multipart feature及分解(炸开)代码文章的复制版本,但是有一个问题,他的代码中有一个变量GeometryHelper未明确说明,无法验证代码可行与否,所幸找到如下一篇文章
explode multiPart 炸开多部件(复杂对象)又称为多部分: https://blog.csdn.net/gishys/article/details/55100655
较好的解决了我的问题:
其思路为先将multipart feature包含的各个Geometry取出来,以创建要素的方式将其添加到图层中;之后再删除原multipart feature
public void ExplodeMultipart(IFeatureClass ExFeature) { IFeatureCursor mFeatureCursor = ExFeature.Update(null, false); IFeature mFeature = mFeatureCursor.NextFeature(); IWorkspace del_workspace = (ExFeature as IDataset).Workspace; IWorkspaceEdit del_workspaceedit = del_workspace as IWorkspaceEdit; if (del_workspaceedit.IsBeingEdited() == true) del_workspaceedit.StopEditing(true); del_workspaceedit.StartEditing(false); del_workspaceedit.StartEditOperation(); while (mFeature != null) { IGeometryCollection mGeometryCol = mFeature.ShapeCopy as IGeometryCollection; int mGeoCount = mGeometryCol.GeometryCount; int idRemark = -1; if (mGeoCount > 1) { idRemark = int.Parse(mFeature.get_Value(0).ToString()); for (int index = 0; index < mGeoCount; index++) { IFeature mNewFeature = (mFeature.Class as IFeatureClass).CreateFeature(); IFeatureEdit mFeatureEdit = mFeature as IFeatureEdit; mFeatureEdit.SplitAttributes(mNewFeature); IGeometry mGeoNew = mGeometryCol.get_Geometry(index); mGeoNew.SpatialReference = mFeature.Shape.SpatialReference; IGeometryCollection mGCollection = new PolygonClass(); mGCollection.AddGeometry(mGeoNew); mNewFeature.Shape = mGCollection as IGeometry; mNewFeature.Store(); } } if (idRemark != -1) { mFeatureCursor.DeleteFeature(); idRemark = -1; } mFeature = mFeatureCursor.NextFeature(); } del_workspaceedit.StopEditOperation(); del_workspaceedit.StopEditing(true); }
3 Multipart To Singlepart
该工具定义在ArcToolbox/DataManagementTools/Features/Multipart To Singlepart下
3.1 原理描述
创建包含通过分割多部件输入要素而生成的单部件要素的要素类
3.2 使用方法
输入要素的属性将保留在输出要素类中。向输出要素类添加新字段 ORIG_FID,并设置为输入要素 ID。
多部件要素的各个部件在输出要素类中将成为独立的要素。已经是单部件的要素不会受到影响。
大多数输出要素的类型与输入要素的类型相同(输入面仍为面;输入线仍为线)。唯一的例外是当输入要素类型为多点时,输出要素类的类型将为点。
要使用单部件要素根据公用字段值重新构建多部件要素(例如 ORIG_FID),请使用融合工具。
多面体要素将被分为其构成的几何部件。每一部件可定义为包含 X、Y 和 Z 坐标的折点集合,请形式如下所示:
引用 3 个折点的单个三角形。
三角条带由共享同一条公用边的多个三角形定义。
三角扇由具有公用原点的多个三角形定义。
表示由 4 个或更多折点定义边界的共平面区域的圆环。
3.3 语法
MultipartToSinglepart(in_features, out_feature_class)
3.4 python代码示例
MultipartToSinglepart 示例 1(Python 窗口)
以下 Python 窗口脚本演示了如何在即时模式下使用 MultipartToSinglepart 函数。
import arcpy arcpy.env.workspace = "C:/data" arcpy.MultipartToSinglepart_management("landuse.shp","c:/output/output.gdb/landuse_singlepart")
MultipartToSinglepart 示例 2(独立脚本)
以下独立脚本是演示如何在脚本环境中应用 MultipartToSinglepart 函数的简单示例。
# Name: MultipartToSinglepart_Example2.py # Description: Break all multipart features into singlepart features, # and report which features were separated. # Import system modules import arcpy # Create variables for the input and output feature classes inFeatureClass = "c:/data/gdb.gdb/vegetation" outFeatureClass = "c:/data/gdb.gdb/vegetation_singlepart" try: # Create list of all fields in inFeatureClass fieldNameList = [field.name for field in arcpy.ListFields(inFeatureClass)] # Add a field to the input this will be used as a unique identifier arcpy.AddField_management(inFeatureClass, "tmpUID", "double") # Determine what the name of the Object ID is OIDFieldName = arcpy.Describe(inFeatureClass).OIDFieldName # Calculate the tmpUID to the OID arcpy.CalculateField_management(inFeatureClass, "tmpUID", "!" + OIDFieldName + "!", "PYTHON") # Run the tool to create a new fc with only singlepart features arcpy.MultipartToSinglepart_management(inFeatureClass, outFeatureClass) # Check if there is a different number of features in the output # than there was in the input inCount = int(arcpy.GetCount_management(inFeatureClass).getOutput(0)) outCount = int(arcpy.GetCount_management(outFeatureClass).getOutput(0)) if inCount != outCount: # If there is a difference, print out the FID of the input # features which were multipart arcpy.Frequency_analysis(outFeatureClass, outFeatureClass + "_freq", "tmpUID") # Use a search cursor to go through the table, and print the tmpUID print("Multipart features from {0}".format(inFeatureClass)) for row in arcpy.da.SearchCursor(outFeatureClass + "_freq", ["tmpUID"], "FREQUENCY > 1"): print(int(row[0])) else: print("No multipart features were found") except arcpy.ExecuteError: print(arcpy.GetMessages()) except Exception as err: print(err.args[0])
官方注解网址:https://pro.arcgis.com/zh-cn/pro-app/tool-reference/data-management/multipart-to-singlepart.htm