ArcGIS Editor工具,实现要素拖动、编辑
2009-02-20 13:32
489 查看
ArcGIS Editor工具,实现要素拖动、编辑
本来根本没有写这个工具的意思,自己一直用的Ae自带的工 具。虽然可控制力弱了一些,但终究还是凑或能用。首先,说一下,所有的要素的更新、插入、删除最好放在编辑的Session 里面,即以一对StartEditing和StopEditing包裹。
一开始我的疑问在于,为什么我用IWorkspaceEdit的StartEditing方法后,怎么鼠标不会变成AcrMap里面Editor的开始编 辑那样呢,为什么不能选中要素,为什么不能双击后编辑要素?原来,选中要素和使要素处于编辑状态还是要自己写的(经高人指点,呵呵)。
先介绍一下程序中用到的变量:
复制内容到剪贴板
代码:
那我们就按照逻辑顺序来一一展示这个到底是怎么做的。首先是,开始和结束编辑的代码: 复制内容到剪贴板
代码:
复制内容到剪贴板
代码:
相信大家对第一个函数并不陌生吧?对的,就是用的空间查询,把点击中的要素放进容器,再用第二个函数进行高亮显示。这个地方注意,如果数据量比较多,强烈推荐用PartialRefresh 而不要用Refresh,参数的含义请参考帮助。
复制内容到剪贴板
代码:
注意,这个函数是在MapControl的AfterDraw里面调用的,IDisplay参数,是AfterDraw事件的参数,我这里就没有画出来,类似ArcMap里面还有一个红色的节点,这里全是绿色的,因为红色对我的用处不大,也就没有必要了,当然各位看官可以自行修改,还有就是绘制符号的时候一定要记得释放内存哦~
现在,编辑状态做好了,但是现在只是雏形,因为它还没有响应任何鼠标事件,当鼠标悬停在绿色的节点上时并不会让你可以拖拽,所以我们还要做点工作。
那现在就开始如果鼠标悬停在绿色节点上时的代码吧:
复制内容到剪贴板
代码:
这里就是根据鼠标悬停的位置,来改变鼠标样式,抱歉的很,我没有从AE里面找到和ArcMap一 样的鼠标样式,只要用一些简单的替代了,当然你可以自己定义,也可以打电话、发Email质问ESRI客服,如果你知道了,一定要告诉我,否则我诅咒你找 不到女朋友!这个函数里面,我需要判断,鼠标是悬停在要素的节点上,还是悬停在要素内部了,这个对于后面处理是拽节点还是移动要素有很大的帮助。
这个根据鼠标悬停位置改变鼠标样式,还远远不够滴,当你悬停到绿色节点上时,按下鼠标时,就意味这拖 拽开始,当鼠标左键按下并移动时,要出现像橡皮筋一样的连接线,当左键弹起时,就意味着拖拽结束,如果再按下左键,就意味着要素的编辑结束。这个怎么做到 呢,请看下面的代码:
public bool EditFeature(int x,int y,IGeometry geometry)
{
GetFeatureOnMouseDown(x, y);
SelectOnMouseDown();
if(m_SelectedFeature.Count<1)return false;
if (geometry == null) return false;
IPoint pHitPoint=null;
double hitDist = 0, tol = 0;
int vertexIndex = 0, vertexOffset = 0, numVertices = 0, partIndex = 0;
bool vertex=false;
IFeature editedFeature = m_SelectedFeature[0];
point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
tol = ConvertPixelsToMapUnits(4);
//IGeometry pGeo = editedFeature.Shape;
//m_EditingFeature = editedFeature;
try
{
switch (geometry.GeometryType)
{
case esriGeometryType.esriGeometryPoint:
m_FeedBack = new MovePointFeedbackClass();
m_FeedBack.Display = m_MapControl.ActiveView.ScreenDisplay;
IMovePointFeedback pointMove = m_FeedBack as IMovePointFeedback;
pointMove.Start(geometry as IPoint, point);
break;
case esriGeometryType.esriGeometryPolyline:
if (TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex))
{
if(!vertex)
{
IGeometryCollection geometryColl = geometry as IGeometryCollection;
IPath path = geometryColl.get_Geometry(partIndex) as IPath;
IPointCollection pointColl = path as IPointCollection;
numVertices = pointColl.PointCount;
object missing = Type.Missing;
if (vertexIndex == 0)
{
object start = 1 as object;
pointColl.AddPoint(point, ref start, ref missing);
}
else
{
object objVertexIndex=vertexIndex as object;
pointColl.AddPoint(point, ref missing, ref objVertexIndex);
}
TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex);
}
m_FeedBack = new LineMovePointFeedbackClass();
m_FeedBack.Display = m_MapControl.ActiveView.ScreenDisplay;
ILineMovePointFeedback lineMove = m_FeedBack as ILineMovePointFeedback;
lineMove.Start(geometry as IPolyline, vertexIndex, point);
}
else return false;
break;
case esriGeometryType.esriGeometryPolygon:
if (TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex))
{
if(!vertex)
{
IGeometryCollection geometryColl = geometry as IGeometryCollection;
IPath path = geometryColl.get_Geometry(partIndex) as IPath;
IPointCollection pointColl = path as IPointCollection;
numVertices = pointColl.PointCount;
object missing = Type.Missing;
if (vertexIndex == 0)
{
object start = 1 as object;
pointColl.AddPoint(point, ref start, ref missing);
}
else
{
object objVertexIndex = vertexIndex as object;
pointColl.AddPoint(point, ref missing, ref objVertexIndex);
}
TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex);
}
m_FeedBack = new PolygonMovePointFeedbackClass();
m_FeedBack.Display = m_MapControl.ActiveView.ScreenDisplay;
IPolygonMovePointFeedback polyMove = m_FeedBack as IPolygonMovePointFeedback;
polyMove.Start(geometry as IPolygon, vertexIndex + vertexOffset, point);
}
else return false;
break;
default:
break;
}
}
catch {return false;}
return true;
}
public void FeatureEditMouseMove(int x,int y)
{
if (m_FeedBack == null) return;
IPoint point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
m_FeedBack.MoveTo(point);
}
public IGeometry EndFeatureEdit(int x, int y)
{
if (m_FeedBack == null) return null;
IGeometry geometry = null;
IPoint point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
if ((m_FeedBack as IMovePointFeedback) != null)
{
IMovePointFeedback pointMove = m_FeedBack as IMovePointFeedback;
geometry = pointMove.Stop() as IGeometry;
}
else if ((m_FeedBack as ILineMovePointFeedback) != null)
{
ILineMovePointFeedback lineMove = m_FeedBack as ILineMovePointFeedback;
geometry = lineMove.Stop() as IGeometry;
}
else if ((m_FeedBack as IPolygonMovePointFeedback) != null)
{
IPolygonMovePointFeedback polyMove = m_FeedBack as IPolygonMovePointFeedback;
geometry = polyMove.Stop() as IGeometry;
}
m_FeedBack = null;
m_MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, m_SelectedLayer, null);
return geometry;
}
呵,这个排版真的是很累啊,无法自动缩进,害的我只能一行一行的移动。第一个函数,自然是点击下绿色 节点时触发,意味着,我们的拖拽就开始了;但是,但按着鼠标左键来回移动时怎么处理啊?呵呵,这就是第二个函数的所具备的功能,所以你要在 MapControl 的MouseMove事件中添加这个函数;但是当你确定你移动的位置是最佳位置的时候,想停下来怎么办呢?这就是第三个函数来帮你了,也就意味着你的拖拽 结束,并返回一个IGeometry,这个IGeometry就是你编辑过后要素的新的几何形状,并且当你移动结束左键弹起的时候,这个新的 IGeometry也需要显示出来它的绿色的节点,所以重绘的时候需要这个IGeometry。 好了,我们快大功告成了,stop!好像还少点东西,对了,我们最终是要把最新的几何形状赋给编辑的要素以实现更新,所以我们还需要下面的这个函数:
复制内容到剪贴板
代码:
呵呵,对的,这个函数很简单,就是更新一下编辑要素的几何形状,注意啊,这里我获取当前编辑的要素是从容器中取出来的,这样是不是很方便啊?这样我们就可以更新一个要素了。别忘了最后记得调用StopEditing以保存你的编辑!
当然,不可能一次性做好,我们需要更人性化一点,我们需要添加撤销和重做:
复制内容到剪贴板
代码:
呵呵 这个也是很简单,对吧?这里需要给出几个上述函数中用到的辅助函数,这里就不一一阐明了,请各位看官自行分析:
代码:
希望大家能够有所启发,谢谢大家的支持!
本来根本没有写这个工具的意思,自己一直用的Ae自带的工 具。虽然可控制力弱了一些,但终究还是凑或能用。首先,说一下,所有的要素的更新、插入、删除最好放在编辑的Session 里面,即以一对StartEditing和StopEditing包裹。
一开始我的疑问在于,为什么我用IWorkspaceEdit的StartEditing方法后,怎么鼠标不会变成AcrMap里面Editor的开始编 辑那样呢,为什么不能选中要素,为什么不能双击后编辑要素?原来,选中要素和使要素处于编辑状态还是要自己写的(经高人指点,呵呵)。
先介绍一下程序中用到的变量:
复制内容到剪贴板
代码:
private AxMapControl m_MapControl;//从外部传进来的MapControl控件 private ILayer m_SelectedLayer;//当前正在编辑的图层 private bool m_IsEdited = false;//当前是否处于编辑状态 private bool m_IsInUse = false;//这个其实我这里没有用到,这个实在创建新要素时用到的 private List m_SelectedFeature;//这个存储鼠标点击下,击中的要素 private IPoint m_CurrentMousePosition;//这个好像也没用到,记录当前鼠标的位置 private IDisplayFeedback m_FeedBack;//这个就是当前屏幕(鼠标动作)的反馈信息
那我们就按照逻辑顺序来一一展示这个到底是怎么做的。首先是,开始和结束编辑的代码: 复制内容到剪贴板
代码:
/// /// 开始编辑 /// /// public void StartEditing(bool bWithUndoRedo) { if (m_SelectedLayer == null) return; IFeatureLayer featureLayer = m_SelectedLayer as IFeatureLayer; if (featureLayer == null) return; IFeatureClass featureClass = featureLayer.FeatureClass; if (featureClass == null) return; IDataset dataset = featureClass as IDataset; IWorkspaceEdit workspaceEdit = dataset.Workspace as IWorkspaceEdit; try { workspaceEdit.StartEditing(bWithUndoRedo); m_IsEdited = true; } catch { return; } } 当然你可以直接传进来IWorkspace,这个可根据你具体的需求,我这里用当前图层获取工作空间。 /// /// 结束编辑 /// /// public void StopEditing(bool bSave) { if (m_IsEdited) { m_IsEdited = false; if (m_SelectedLayer == null) return; IFeatureLayer featureLayer = m_SelectedLayer as IFeatureLayer; if (featureLayer == null) return; IFeatureClass featureClass = featureLayer.FeatureClass; if (featureClass == null) return; IDataset dataset = featureClass as IDataset; IWorkspaceEdit workspaceEdit = dataset.Workspace as IWorkspaceEdit; if (workspaceEdit.IsBeingEdited()) { try { workspaceEdit.StopEditing(bSave); } catch { workspaceEdit.AbortEditOperation(); return; } } } }
开始编辑已经好了,然后就是鼠标点击要素时候,让其处于选中状态,我这里为了方便控制,我分成了两个函数写,给为看官也可以合并成一个:
复制内容到剪贴板
代码:
public void GetFeatureOnMouseDown(int x, int y) { m_SelectedFeature.Clear(); try { if (m_SelectedLayer == null) return; IFeatureLayer featureLayer = m_SelectedLayer as IFeatureLayer; if (featureLayer == null) return; IFeatureClass featureClass = featureLayer.FeatureClass; if (featureClass == null) return; IPoint point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y); IGeometry geometry = point as IGeometry; double length = ConvertPixelsToMapUnits(4); ITopologicalOperator pTopo = geometry as ITopologicalOperator; IGeometry buffer = pTopo.Buffer(length); geometry = buffer.Envelope as IGeometry; ISpatialFilter spatialFilter = new SpatialFilterClass(); spatialFilter.Geometry = geometry; switch (featureClass.ShapeType) { case esriGeometryType.esriGeometryPoint: spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains; break; case esriGeometryType.esriGeometryPolygon: spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects; break; case esriGeometryType.esriGeometryPolyline: spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelCrosses; break; } spatialFilter.GeometryField = featureClass.ShapeFieldName; IQueryFilter filter = spatialFilter as IQueryFilter; IFeatureCursor cursor = featureClass.Search(filter, false); IFeature pfeature = cursor.NextFeature(); while (pfeature != null) { m_SelectedFeature.Add(pfeature); pfeature = cursor.NextFeature(); } } catch { return; } } /// /// 根据鼠标点击位置使击中要素处于高亮显示状态 /// /// /// public void SelectOnMouseDown() { try { if (m_SelectedLayer == null) return; m_MapControl.Map.ClearSelection(); m_MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null); foreach (IFeature feature in m_SelectedFeature.ToArray()) { m_MapControl.Map.SelectFeature(m_SelectedLayer, feature); } m_MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null); } catch { return; } }
相信大家对第一个函数并不陌生吧?对的,就是用的空间查询,把点击中的要素放进容器,再用第二个函数进行高亮显示。这个地方注意,如果数据量比较多,强烈推荐用PartialRefresh 而不要用Refresh,参数的含义请参考帮助。
这个只是开始编辑后,可以用鼠标点击选中要素,使其处于高亮状态,然而,ArcMap里面双击要素怎么出现节点用以编辑呢?这个是要自己绘制到MapControl上面去的:
复制内容到剪贴板
代码:
/// /// 在要素上面绘制一个可拖拽的符号 /// /// public void DrawEditSymbol(IGeometry geometry, IDisplay display) { IEngineEditProperties engineProperty = new EngineEditorClass(); ISymbol pointSymbol = engineProperty.SketchVertexSymbol as ISymbol; ISymbol sketchSymbol = engineProperty.SketchSymbol as ISymbol; ITopologicalOperator pTopo = geometry as ITopologicalOperator; sketchSymbol.SetupDC(display.hDC, display.DisplayTransformation); sketchSymbol.Draw(pTopo.Boundary); IPointCollection pointCol = geometry as IPointCollection; for (int i = 0; i < pointCol.PointCount; i++) { IPoint point = pointCol.get_Point(i); pointSymbol.SetupDC(display.hDC, display.DisplayTransformation); pointSymbol.Draw(point); pointSymbol.ResetDC(); } ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(sketchSymbol); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(pointSymbol); ESRI.ArcGIS.ADF.ComReleaser.ReleaseCOMObject(engineProperty); }
注意,这个函数是在MapControl的AfterDraw里面调用的,IDisplay参数,是AfterDraw事件的参数,我这里就没有画出来,类似ArcMap里面还有一个红色的节点,这里全是绿色的,因为红色对我的用处不大,也就没有必要了,当然各位看官可以自行修改,还有就是绘制符号的时候一定要记得释放内存哦~
现在,编辑状态做好了,但是现在只是雏形,因为它还没有响应任何鼠标事件,当鼠标悬停在绿色的节点上时并不会让你可以拖拽,所以我们还要做点工作。
那现在就开始如果鼠标悬停在绿色节点上时的代码吧:
复制内容到剪贴板
代码:
public void SnapVertex(int x,int y,IGeometry snapContainer,ref bool vertexSnaped,ref bool contained) { IPoint point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y); IPoint pHitPoint = null; double hitDist = -1, tol = -1; int vertexIndex = -1, partIndex = -1; bool vertex = false; tol = ConvertPixelsToMapUnits(4); IHitTest pHitTest = snapContainer as IHitTest; bool bHit=pHitTest.HitTest(point, tol, esriGeometryHitPartType.esriGeometryPartVertex, pHitPoint, ref hitDist, ref partIndex, ref vertexIndex, ref vertex); vertexSnaped = false; contained = false; if (bHit) { m_MapControl.MousePointer = esriControlsMousePointer.esriPointerCrosshair; vertexSnaped = true; return; } else { IRelationalOperator pRelOperator=null; ITopologicalOperator pTopo = null; IGeometry buffer = null; IPolygon polygon = null; switch (snapContainer.GeometryType) { case esriGeometryType.esriGeometryPolyline: pTopo = snapContainer as ITopologicalOperator; buffer=pTopo.Buffer(3); polygon = buffer as IPolygon; pRelOperator=polygon as IRelationalOperator; break; case esriGeometryType.esriGeometryPolygon: polygon = snapContainer as IPolygon; pRelOperator=polygon as IRelationalOperator; break; case esriGeometryType.esriGeometryPoint: pTopo = snapContainer as ITopologicalOperator; buffer = pTopo.Buffer(3); polygon = buffer as IPolygon; pRelOperator = polygon as IRelationalOperator; break; default: break; } if (pRelOperator == null) return; if (pRelOperator.Contains(point)) { m_MapControl.MousePointer = esriControlsMousePointer.esriPointerSizeAll; contained = true; } else m_MapControl.MousePointer = esriControlsMousePointer.esriPointerArrow; return; } }
这里就是根据鼠标悬停的位置,来改变鼠标样式,抱歉的很,我没有从AE里面找到和ArcMap一 样的鼠标样式,只要用一些简单的替代了,当然你可以自己定义,也可以打电话、发Email质问ESRI客服,如果你知道了,一定要告诉我,否则我诅咒你找 不到女朋友!这个函数里面,我需要判断,鼠标是悬停在要素的节点上,还是悬停在要素内部了,这个对于后面处理是拽节点还是移动要素有很大的帮助。
这个根据鼠标悬停位置改变鼠标样式,还远远不够滴,当你悬停到绿色节点上时,按下鼠标时,就意味这拖 拽开始,当鼠标左键按下并移动时,要出现像橡皮筋一样的连接线,当左键弹起时,就意味着拖拽结束,如果再按下左键,就意味着要素的编辑结束。这个怎么做到 呢,请看下面的代码:
public bool EditFeature(int x,int y,IGeometry geometry)
{
GetFeatureOnMouseDown(x, y);
SelectOnMouseDown();
if(m_SelectedFeature.Count<1)return false;
if (geometry == null) return false;
IPoint pHitPoint=null;
double hitDist = 0, tol = 0;
int vertexIndex = 0, vertexOffset = 0, numVertices = 0, partIndex = 0;
bool vertex=false;
IFeature editedFeature = m_SelectedFeature[0];
point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
tol = ConvertPixelsToMapUnits(4);
//IGeometry pGeo = editedFeature.Shape;
//m_EditingFeature = editedFeature;
try
{
switch (geometry.GeometryType)
{
case esriGeometryType.esriGeometryPoint:
m_FeedBack = new MovePointFeedbackClass();
m_FeedBack.Display = m_MapControl.ActiveView.ScreenDisplay;
IMovePointFeedback pointMove = m_FeedBack as IMovePointFeedback;
pointMove.Start(geometry as IPoint, point);
break;
case esriGeometryType.esriGeometryPolyline:
if (TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex))
{
if(!vertex)
{
IGeometryCollection geometryColl = geometry as IGeometryCollection;
IPath path = geometryColl.get_Geometry(partIndex) as IPath;
IPointCollection pointColl = path as IPointCollection;
numVertices = pointColl.PointCount;
object missing = Type.Missing;
if (vertexIndex == 0)
{
object start = 1 as object;
pointColl.AddPoint(point, ref start, ref missing);
}
else
{
object objVertexIndex=vertexIndex as object;
pointColl.AddPoint(point, ref missing, ref objVertexIndex);
}
TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex);
}
m_FeedBack = new LineMovePointFeedbackClass();
m_FeedBack.Display = m_MapControl.ActiveView.ScreenDisplay;
ILineMovePointFeedback lineMove = m_FeedBack as ILineMovePointFeedback;
lineMove.Start(geometry as IPolyline, vertexIndex, point);
}
else return false;
break;
case esriGeometryType.esriGeometryPolygon:
if (TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex))
{
if(!vertex)
{
IGeometryCollection geometryColl = geometry as IGeometryCollection;
IPath path = geometryColl.get_Geometry(partIndex) as IPath;
IPointCollection pointColl = path as IPointCollection;
numVertices = pointColl.PointCount;
object missing = Type.Missing;
if (vertexIndex == 0)
{
object start = 1 as object;
pointColl.AddPoint(point, ref start, ref missing);
}
else
{
object objVertexIndex = vertexIndex as object;
pointColl.AddPoint(point, ref missing, ref objVertexIndex);
}
TestGeometryHit(tol, point, geometry, ref pHitPoint, ref hitDist, ref partIndex, ref vertexOffset, ref vertexIndex, ref vertex);
}
m_FeedBack = new PolygonMovePointFeedbackClass();
m_FeedBack.Display = m_MapControl.ActiveView.ScreenDisplay;
IPolygonMovePointFeedback polyMove = m_FeedBack as IPolygonMovePointFeedback;
polyMove.Start(geometry as IPolygon, vertexIndex + vertexOffset, point);
}
else return false;
break;
default:
break;
}
}
catch {return false;}
return true;
}
public void FeatureEditMouseMove(int x,int y)
{
if (m_FeedBack == null) return;
IPoint point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
m_FeedBack.MoveTo(point);
}
public IGeometry EndFeatureEdit(int x, int y)
{
if (m_FeedBack == null) return null;
IGeometry geometry = null;
IPoint point = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
if ((m_FeedBack as IMovePointFeedback) != null)
{
IMovePointFeedback pointMove = m_FeedBack as IMovePointFeedback;
geometry = pointMove.Stop() as IGeometry;
}
else if ((m_FeedBack as ILineMovePointFeedback) != null)
{
ILineMovePointFeedback lineMove = m_FeedBack as ILineMovePointFeedback;
geometry = lineMove.Stop() as IGeometry;
}
else if ((m_FeedBack as IPolygonMovePointFeedback) != null)
{
IPolygonMovePointFeedback polyMove = m_FeedBack as IPolygonMovePointFeedback;
geometry = polyMove.Stop() as IGeometry;
}
m_FeedBack = null;
m_MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, m_SelectedLayer, null);
return geometry;
}
呵,这个排版真的是很累啊,无法自动缩进,害的我只能一行一行的移动。第一个函数,自然是点击下绿色 节点时触发,意味着,我们的拖拽就开始了;但是,但按着鼠标左键来回移动时怎么处理啊?呵呵,这就是第二个函数的所具备的功能,所以你要在 MapControl 的MouseMove事件中添加这个函数;但是当你确定你移动的位置是最佳位置的时候,想停下来怎么办呢?这就是第三个函数来帮你了,也就意味着你的拖拽 结束,并返回一个IGeometry,这个IGeometry就是你编辑过后要素的新的几何形状,并且当你移动结束左键弹起的时候,这个新的 IGeometry也需要显示出来它的绿色的节点,所以重绘的时候需要这个IGeometry。 好了,我们快大功告成了,stop!好像还少点东西,对了,我们最终是要把最新的几何形状赋给编辑的要素以实现更新,所以我们还需要下面的这个函数:
复制内容到剪贴板
代码:
public bool UpdateEdit(IGeometry newGeom) { if (m_SelectedFeature.Count < 1) return false; if (newGeom == null) return false; if (newGeom.IsEmpty) return false; IFeature feature = m_SelectedFeature[0]; IDataset dataset = feature.Class as IDataset; IWorkspaceEdit workspaceEdit = dataset.Workspace as IWorkspaceEdit; if (!workspaceEdit.IsBeingEdited()) return false; workspaceEdit.StartEditOperation(); feature.Shape = newGeom; feature.Store(); workspaceEdit.StopEditOperation(); m_SelectedFeature.Clear(); m_SelectedFeature.Add(feature); ClearSelection(); return true; }
呵呵,对的,这个函数很简单,就是更新一下编辑要素的几何形状,注意啊,这里我获取当前编辑的要素是从容器中取出来的,这样是不是很方便啊?这样我们就可以更新一个要素了。别忘了最后记得调用StopEditing以保存你的编辑!
当然,不可能一次性做好,我们需要更人性化一点,我们需要添加撤销和重做:
复制内容到剪贴板
代码:
public void UndoEdit() { if (m_SelectedLayer == null) return; IFeatureLayer featLayer = m_SelectedLayer as IFeatureLayer; IDataset dataset = featLayer.FeatureClass as IDataset; IWorkspaceEdit workspaceEdit = dataset.Workspace as IWorkspaceEdit; bool bHasUndos = false; workspaceEdit.HasUndos(ref bHasUndos); if(bHasUndos) { workspaceEdit.UndoEditOperation(); } ClearSelection(); } public void RedoEdit() { if (m_SelectedLayer == null) return; IFeatureLayer featLayer = m_SelectedLayer as IFeatureLayer; IDataset dataset = featLayer.FeatureClass as IDataset; IWorkspaceEdit workspaceEdit = dataset.Workspace as IWorkspaceEdit; bool bHasUndos = false; workspaceEdit.HasRedos(ref bHasUndos); if (bHasUndos) { workspaceEdit.RedoEditOperation(); } ClearSelection(); }
呵呵 这个也是很简单,对吧?这里需要给出几个上述函数中用到的辅助函数,这里就不一一阐明了,请各位看官自行分析:
代码:
private double ConvertPixelsToMapUnits(double pixelUnits) { int pixelExtent = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.get_DeviceFrame().right- m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.get_DeviceFrame().left; double realWorldDisplayExtent = m_MapControl.ActiveView.ScreenDisplay.DisplayTransformation.VisibleBounds.Width; double sizeOfOnePixel = realWorldDisplayExtent / pixelExtent; r eturn pixelUnits * sizeOfOnePixel; } private bool TestGeometryHit(double tol,IPoint pPoint,IGeometry geometry,ref IPoint pHitPoint, ref double hitDist, ref int partIndex, ref int vertexOffset, ref int vertexIndex, ref bool vertexHit) { IHitTest pHitTest = geometry as IHitTest; pHitPoint = new PointClass(); bool last = true; bool res = false; if (pHitTest.HitTest(pPoint, tol, esriGeometryHitPartType.esriGeometryPartVertex, pHitPoint, ref hitDist, ref partIndex, ref vertexIndex, ref last)) { vertexHit = true; res = true; } else { if (pHitTest.HitTest(pPoint, tol, esriGeometryHitPartType.esriGeometryPartBoundary, pHitPoint, ref hitDist, ref partIndex, ref vertexIndex, ref last)) { vertexHit = false; res = true; } } if(partIndex>0) { IGeometryCollection pGeoColl = geometry as IGeometryCollection; vertexOffset = 0; for (int i = 0; i < partIndex;i=2*i+1) { IPointCollection pointColl = pGeoColl.get_Geometry(i) as IPointCollection; vertexOffset = vertexOffset + pointColl.PointCount; } } return res; } /// /// 清除要素选择状态,恢复常态 /// public void ClearSelection() { m_MapControl.Map.ClearSelection(); m_MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, m_SelectedLayer, null); }各位看官,由于要素的移动、要素的创建和要素编辑在代码逻辑上差不多,所以我就不做过多阐述了,都是在处理鼠标的事件,需要做判断。其实,可能有看官已经了解,在AE的帮助里面就有类似的代码,是的,我参考了这部分代码,并对ESRI的开发和工作人员表示感谢。
希望大家能够有所启发,谢谢大家的支持!
相关文章推荐
- ArcMap的Editor工具,实现要素拖动、编辑、节点删除
- ArcMap的Editor工具,实现要素拖动、编辑
- ArcMap的Editor工具,实现要素拖动、编辑。
- ArcGIS Engine 节点编辑,实现要素拖动、编辑、节点删除
- 请教方法和例子:VS2003的datagrid控件,如何实现用鼠标拖动的方法选中任意区域的多个单元格,然后进行统一编辑??
- C#软件开发实例.私人订制自己的屏幕截图工具(十一)编辑工具栏的实现
- javascript实现div的拖动并调整大小类似qq空间个性编辑模块
- 基于Qt的截图工具,实现截图后进行编辑
- ArcGIS API for Javascript 实现在线要素编辑(二)
- 【转】WebGIS实现要素在线编辑之Silverlight调用FeatureService实现编辑功能
- WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析
- WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析
- 基于Qt的截图工具,实现截图后进行编辑
- ArcGIS API for Javascript 实现在线要素编辑(一)
- javascript实现div的拖动并调整大小类似qq空间个性编辑模块
- c#+ ArcgisEngine 定制要素编辑工具
- 数据编辑中 实现要素捕捉
- 基于Qt的截图工具,实现截图后进行编辑
- [置顶] Qt读写Xml文件、QTreeWidget项实现可拖动、编辑、添加、删除等
- WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析