1. 程式人生 > 實用技巧 >元件GIS 4 空間編輯

元件GIS 4 空間編輯

目錄

TODO:屬性表”屬性修改“,屬性表”欄位計算器“,”非建立要素過程中”的撤銷重做。

4.1 綱要

4.1.1 思維導圖

4.1.2 介面、列舉

  • IEngineEditor,IEngineEditSketch,IEngineSketchOperation
  • IPoint,IPointCollection,IGeometry,IGeometryCollection

4.1.3 效果動態圖

4.2 編輯命令

撤銷重做包括“建立要素”過程中和非“建立要素”過程中,難度較大。

4.2.1 開始編輯

//1 獲取目標圖層
cboEditingLyr.Items.Clear();
List<string> targetEditingLyr = BasicClass.GetFeatureLayerNameList(axMapControl.Map);
cboEditingLyr.Items.AddRange(targetEditingLyr.ToArray());
cboEditingLyr.SelectedIndex = 0;
//2 獲取工作空間&開始編輯
IDataset pSet = (IDataset)m_pFeaLyr.FeatureClass;
IWorkspace pWs = pSet.Workspace;
m_pEditor.EnableUndoRedo(true);//開啟撤銷重做
m_pEditor.StartEditing(pWs, axMapControl.Map);

4.2.2 儲存編輯

DialogResult isSave = MessageBox.Show("是否儲存編輯?", "提示",
                                      MessageBoxButtons.YesNo, MessageBoxIcon.Question);
IWorkspace pWs = m_pEditor.EditWorkspace;
if (isSave == DialogResult.Yes)
{
    m_pEditor.StopEditing(true);
    m_pEditor.StartEditing(pWs, axMapControl.Map);
    axMapControl.Refresh();
}

4.2.3 停止編輯

DialogResult isSave = MessageBox.Show("是否儲存編輯?", "提示",
                                      MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (isSave == DialogResult.Yes)
    m_pEditor.StopEditing(true);
else
    m_pEditor.StopEditing(false);

4.2.4 撤銷重做(建立要素過程中)

找了草圖工具建立要素過程中撤銷重做的官方介面很久,嘗試了IEngineEditSketch,IEngineSketchOperation,IOperationStack介面發現效果並不是我想要的,最後只能確定官方不提供,只能用C#的堆疊類實現。

注:建議先看”建立要素“思路程式碼。

撤銷

1. 初檢:草圖工具Geometry屬性不為空;
2. 入棧:草圖工具最後一個點;備份點棧;
3. 轉為點串;
4. 刪除最後一個點(面要素是倒數第二個點);
5. 複檢:草圖工具Geometry屬性為空→關閉撤銷許可。
//1 初檢
if (!m_pSketch.Geometry.IsEmpty)
{
    //2 入棧
    m_pPntStack.Push(m_pSketch.LastPoint);
    m_pPntStackCopy = m_pPntStack;//備份
    //3 刪除
    IPointCollection pPntCol = (IPointCollection)m_pSketch.Geometry;
    if (m_pSketch.GeometryType == esriGeometryType.esriGeometryPolygon
        && pPntCol.PointCount > 1)
        pPntCol.RemovePoints(pPntCol.PointCount - 2, 1);
    else
        pPntCol.RemovePoints(pPntCol.PointCount - 1, 1);
    m_pSketch.Geometry = (IGeometry)pPntCol;
    //4 複檢/更新許可
    if (m_pSketch.Geometry.IsEmpty)
        canUndo = false;
    canRedo = true;
}
//5 重新整理
m_pHookHelper.ActiveView.Refresh();

重做

1. 初檢:棧內要素不為空;
2. 出棧:獲取一個點;
3. 加點:草圖工具新增一個點;
4. 複檢:點棧為空→從備份棧獲取,關閉重做許可。
//1 初檢
if (m_pPntStack.Count > 0)
{
    //2 出棧
    IPoint pPnt = m_pPntStack.Pop();
    //3 複檢
    if (m_pPntStack.Count == 0)
    {
        m_pPntStack = m_pPntStackCopy;
        canRedo = false;
    }
    //4 新增
    m_pSketch.AddPoint(pPnt, true);
    //5 許可
    canUndo = true;
}
//6 重新整理
m_pHookHelper.ActiveView.Refresh();

快捷鍵設定

給axMapControl.ContextMenu屬性賦值一個右鍵選單。

4.3 要素編輯

4.3.1 建立要素

新建CreateFeatureTool類,實現ICommand和ITool介面,關鍵程式碼在ITool成員的OnMouseDown的響應事件中實現

public void OnMouseDown(int button, int shift, int x, int y)
{
    //轉成地圖座標
    IPoint point = m_pHookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
    if (button == 1)
    {
        m_pSketch.AddPoint(point, true);//新增點
        m_pPntStack.Clear();//清空棧
        m_pPntStackCopy.Clear();//清空備份棧
        canUndo = true;//允許撤銷
        isFinishedSketch = false;//建立要素過程中
    }
}

//完成草圖
public void OnDblClick()
{
    m_pSketch.FinishSketch();
    isFinishedSketch = true;
}

4.3.2 移動要素

使用元件庫ICommand cmd = new ControlsEditingEditToolClass();

4.3.3 刪除要素

使用元件庫ICommand cmd = new ControlsEditingEditToolClass();

4.4 結點編輯

要理解”IHitTest.HitTest“引數

bool isTrue = hitShape.HitTest(點選點, 搜尋範圍, 搜尋型別, 反饋點, ref 反饋距離,
                     ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);

4.4.1 結點插入

參考幫助文件”CustomVertexCommands“,”EditingVertexCommands“。

public void OnMouseDown(int button, int shift, int x, int y)
{
    //轉成地圖座標
    IPoint clickedPt = m_pHookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
    if (button == 1)
    {
        #region 1 獲取點選測試引數
            IHitTest hitShape = (IHitTest)m_pSketch.Geometry;
        IPoint hitPoint = new PointClass();
        double hitDistance = 0;
        int hitPartIndex = 0;
        int hitSegmentIndex = 0;
        bool bRightSide = false;
        esriGeometryHitPartType hitPartType = esriGeometryHitPartType.esriGeometryPartNone;
        double searchRadius = 50;
        #endregion

        //2 節點判斷
        hitPartType = esriGeometryHitPartType.esriGeometryPartVertex;
        bool isTrue = hitShape.HitTest(clickedPt, searchRadius, hitPartType, hitPoint, ref hitDistance,
                                       ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
        if (isTrue) return; //已存在節點,不需要新增
        //3 點選測試
        hitPartType = esriGeometryHitPartType.esriGeometryPartBoundary;
        isTrue = hitShape.HitTest(clickedPt, searchRadius, hitPartType, hitPoint, ref hitDistance,
                                  ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
        //4 新增節點 
        if (isTrue)
        {
            //4.1 草圖操作開始
            IEngineSketchOperation pSketchOp = new EngineSketchOperationClass();
            pSketchOp.Start(m_pEditor);
            pSketchOp.SetMenuString("Insert Vertex (Custom)");
            //4.2 獲取點串
            IGeometryCollection pGeoCol = (IGeometryCollection)m_pSketch.Geometry;
            IPointCollection pPathOrRingPtCol = (IPointCollection)pGeoCol.get_Geometry(hitPartIndex);
            //4.3 插入節點
            object missing = Type.Missing;
            object hitSegmentIndexObject = hitSegmentIndex;
            object partIndexObject = hitPartIndex;
            pPathOrRingPtCol.AddPoint(hitPoint, ref missing, ref hitSegmentIndexObject);
            //4.4 移除舊的,新增新的
            pGeoCol.RemoveGeometries(hitPartIndex, 1);
            pGeoCol.AddGeometry((IGeometry)pPathOrRingPtCol, ref partIndexObject, ref missing);
            //4.5 草圖操作完成
            esriEngineSketchOperationType opType =
                esriEngineSketchOperationType.esriEngineSketchOperationVertexAdded;
            pSketchOp.Finish(null, opType, hitPoint);
        }
    }
}

4.4.2 結點刪除

public void OnMouseDown(int button, int shift, int x, int y)
{
    //轉成地圖座標
    IPoint clickedPt = m_pHookHelper.ActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
    if (button == 1)
    {
        #region 1 獲取點選測試引數
            IHitTest hitShape = (IHitTest)m_pSketch.Geometry;
        IPoint hitPoint = new PointClass();
        double hitDistance = 0;
        int hitPartIndex = 0;
        int hitSegmentIndex = 0;
        bool bRightSide = false;
        esriGeometryHitPartType hitPartType = esriGeometryHitPartType.esriGeometryPartNone;
        double searchRadius = 50;
        #endregion

        //2 節點判斷
        hitPartType = esriGeometryHitPartType.esriGeometryPartVertex;
        bool isTrue = hitShape.HitTest(clickedPt, searchRadius, hitPartType, hitPoint, ref hitDistance,
                                       ref hitPartIndex, ref hitSegmentIndex, ref bRightSide);
        //3 刪除節點 
        if (isTrue)
        {
            //3.1 草圖操作開始
            IEngineSketchOperation pSketchOp = new EngineSketchOperationClass();
            pSketchOp.Start(m_pEditor);
            pSketchOp.SetMenuString("Delete Vertex (Custom)");
            //3.2 獲取點串
            IGeometryCollection pGeoCol = (IGeometryCollection)m_pSketch.Geometry;
            IPointCollection pPathOrRingPtCol = (IPointCollection)pGeoCol.get_Geometry(hitPartIndex);
            //3.3 刪除節點
            object missing = Type.Missing;
            object partIndexObject = hitPartIndex;
            pPathOrRingPtCol.RemovePoints(hitSegmentIndex, 1);
            //4.4 移除舊的,新增新的
            pGeoCol.RemoveGeometries(hitPartIndex, 1);
            pGeoCol.AddGeometry((IGeometry)pPathOrRingPtCol, ref partIndexObject, ref missing);
            //4.5 草圖操作完成
            esriEngineSketchOperationType opType =
                esriEngineSketchOperationType.esriEngineSketchOperationVertexDeleted;
            pSketchOp.Finish(null, opType, hitPoint);
        }
    }
}

4.4.3 結點移動

使用元件庫ICommand cmd = new ControlsEditingEditToolClass();

4.5 屬性編輯

注:這裡的儲存是儲存在”工作空間“,還沒有儲存到資料庫中,需要點選【儲存編輯】才是真正的儲存在資料庫中

4.5.1 對話方塊佈局

4.5.1 關鍵程式碼

for (int i = 0; i < dgvAttributeEdit.RowCount; i++)
{
    string sFieldName = (string)dgvAttributeEdit.Rows[i].Cells[0].Value;
    object objFieldValue = dgvAttributeEdit.Rows[i].Cells[1].Value;
    if (sFieldName != null && sFieldName != string.Empty
        && !sFieldName.ToUpper().Equals("OBJECTID") && objFieldValue != null)
    {
        int index = m_pFea.Fields.FindField(sFieldName);
        m_pFea.Value[index] = objFieldValue;
    }
}
m_pFea.Store();