組件GIS 1 地圖操作


v20200614:TOC右鍵菜單“柵格圖層”和“矢量圖層”區別顯示;獲取屬性表代碼小優化;

v20200622:內容調整,重寫優化;(該死的強迫症)

1.1 綱要

1.1.1 思維導圖

地圖操作

1.1.2 接口、類、枚舉

  • AxMapControl,AxPageLayoutControl,AxTOCControl,axLicenseControl,IHookHelper(ESRI.ArcGIS.Controls)/(ESRI.ArcGIS.AxControls)
  • IMapDocument,IActiveView,IMap,ILayer,IFeatureLayer,IRasterLayer,IExtentStack(ESRI.ArcGIS.Carto)
  • IWorkspaceFactory,IWorkspace,IFeatureWorkspace,IEnumDataset,IDataset,IFeatureDataset,IFeatureClass,esriDatasetType(ESRI.ArcGIS.Geodatabase)
  • IObjectCopy,esriUnits(ESRI.ArcGIS.esriSystem)
  • ICommand,ITool,ISystemMouseCursor,esriSystemMouseCursor(ESRI.ArcGIS.SystemUI)
  • IEnvelope(ESRI.ArcGIS.Geometry)
  • IDisplayTransformation(ESRI.ArcGIS.Display)

1.2 布局

利用TabControl、ToolStrip、SplitContainer、StatusStrip控件划分菜單區、圖層管理區、視圖區、狀態欄。再加上ArcGIS的MapControl、PageLayoutControl、TOCControl、LicenseControl。最后在Program.cs內添加Runtime許可代碼ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);

每一個TabPage內鑲嵌MenuStrip(支持快捷鍵,沒有分割線,沒有label控件)或者ToolStrip(不支持快捷鍵);每一個菜單項圖標標來源於項目資源文件。

主界面

image-20200622094637112

1.3 文件管理

image-20200622144235628

1.3.1 數據加載

axMapControl控件提供axMapControl.AddLayer(); axMapControl.AddLayerFromFile(); axMapControl.AddShapeFile();三種方法。.shp .lyr文件可以直接調用方法傳入路徑即可,柵格數據需要調用IRasterLayer.CreateFromFilePath(FileName); 方法獲取柵格圖層,然后調用axMapControl.AddLayer()即可。

加載.shp矢量數據

if (ofdAddShp.ShowDialog() == DialogResult.OK)
{
    string[] fileName = ofdAddShp.SafeFileNames;//無路徑文件名
    string path = System.IO.Path.GetDirectoryName(ofdAddShp.FileName);//得到文件夾路徑
    for (int i = 0; i < fileName.Length; i++)
        axMapControl.AddShapeFile(path, fileName[i]);
}

加載柵格數據

if (ofdAddRaster.ShowDialog() == DialogResult.OK)
{
    for (int i = 0; i < ofdAddRaster.FileNames.Length; i++)
    {
        IRasterLayer pRasterLayer = new RasterLayerClass();
        pRasterLayer.CreateFromFilePath(ofdAddRaster.FileNames[i]);
        axMapControl.AddLayer(pRasterLayer);
    }
}

1.3.2 地圖文檔的新建、打開、保存

mxd新建

IMap map = new MapClass();
axMapControl.Map = map;

mxd打開

if (ofdOpenMxd.ShowDialog() == DialogResult.OK)
    axMapControl.LoadMxFile(ofdOpenMxd.FileName);

mxd保存

string sMxdFileName = axMapControl.DocumentFilename;
if (sMxdFileName == null || sMxdFileName == string.Empty)
{
    string sRelPath = Application.StartupPath + @"..\..\..\..\Data";
    string sAbsPath = System.IO.Path.GetFullPath(sRelPath);
    SaveFileDialog pSaveFileDialog = new SaveFileDialog();
    pSaveFileDialog.Title = "請選擇保存路徑";
    pSaveFileDialog.InitialDirectory = sAbsPath;
    pSaveFileDialog.OverwritePrompt = true;
    pSaveFileDialog.Filter = "ArcMap文檔(*.mxd)|*.mxd|ArcMap模板(*.mxt)|*.mxt";
    if (pSaveFileDialog.ShowDialog() == DialogResult.OK)
        sMxdFileName = pSaveFileDialog.FileName;
    else
        return;
}
IMapDocument pMapDocument = new MapDocumentClass();
pMapDocument.New(sMxdFileName);
pMapDocument.ReplaceContents(axMapControl.Map as IMxdContents);
pMapDocument.Save();
MessageBox.Show("保存地圖文檔成功!");

mxd另存為

string sRelPath = Application.StartupPath + @"..\..\..\..\Data";
string sAbsPath = System.IO.Path.GetFullPath(sRelPath);
SaveFileDialog pSaveFileDialog = new SaveFileDialog();
pSaveFileDialog.Title = "請選擇保存路徑";
pSaveFileDialog.InitialDirectory = sAbsPath;
pSaveFileDialog.OverwritePrompt = true;
pSaveFileDialog.Filter = "ArcMap文檔(*.mxd)|*.mxd|ArcMap模板(*.mxt)|*.mxt";
if (pSaveFileDialog.ShowDialog() == DialogResult.OK)
{
    IMapDocument pMapDocument = new MapDocumentClass();
    pMapDocument.New(pSaveFileDialog.FileName);
    pMapDocument.ReplaceContents(axMapControl.Map as IMxdContents);
    pMapDocument.Save();
    MessageBox.Show("保存地圖文檔成功!");
}

1.3.3 打開數據庫

首先要理解工作空間的概念,一個數據庫就是一個工作空間,工作空間內存儲數據集,數據集內部存儲要素類、關系類、柵格數據等。

img img

將打開數據庫內部數據封裝成一個方法(在BasicClass):

public static void AddLayersFromDataset(IWorkspace pWorkspace, AxMapControl axMapControl)
{
    try
    {
        IEnumDataset pEnumDataset = pWorkspace.get_Datasets(esriDatasetType.esriDTAny);
        pEnumDataset.Reset();
        IDataset pDataset = pEnumDataset.Next();
        while (pDataset != null)
        {
            switch (pDataset.Type)
            {
                case esriDatasetType.esriDTFeatureClass:    //要素類
                    {
                        IFeatureWorkspace pFeatureWorkspace = (IFeatureWorkspace)pWorkspace;
                        IFeatureClass pFeaCls = pFeatureWorkspace.OpenFeatureClass(pDataset.Name);
                        IFeatureLayer pFeaLyr = new FeatureLayerClass();
                        pFeaLyr.FeatureClass = pFeaCls;
                        axMapControl.Map.AddLayer(pFeaLyr);
                    }
                    break;
                case esriDatasetType.esriDTFeatureDataset:  //要素集
                    {
                        IFeatureWorkspace pFeatureWorkspace = (IFeatureWorkspace)pWorkspace;
                        IFeatureDataset pFeaDataset = pFeatureWorkspace.OpenFeatureDataset(pDataset.Name);
                        IEnumDataset pEnumFeatureDataset = pFeaDataset.Subsets;
                        pEnumFeatureDataset.Reset();
                        IDataset pDatasetNew = pEnumFeatureDataset.Next();
                        while (pDatasetNew != null)
                        {
                            if (pDatasetNew is IFeatureClass)
                            {
                                IFeatureClass pFeaCls = pFeatureWorkspace.OpenFeatureClass(pDatasetNew.Name);
                                IFeatureLayer pFeaLyr = new FeatureLayerClass();
                                pFeaLyr.FeatureClass = pFeaCls;
                                axMapControl.Map.AddLayer(pFeaLyr);
                            }
                            pDatasetNew = pEnumFeatureDataset.Next();
                        }
                    }
                    break;
                case esriDatasetType.esriDTRasterDataset:   //柵格集
                    MessageBox.Show("還沒寫哦!");
                    break;
                case esriDatasetType.esriDTTable:           //表格
                    MessageBox.Show("還沒寫哦!");
                    break;
                case esriDatasetType.esriDTTopology:        //拓撲
                    MessageBox.Show("還沒寫哦!");
                    break;
                default:
                    MessageBox.Show("還沒寫哦!");
                    break;
            }
            pDataset = pEnumDataset.Next();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

1.4 地圖瀏覽

image-20200622144254091

平移:在菜單點擊事件修改axMapControl.MousePointer屬性,在axMapControl的鼠標按下事件內調用axMapControl.Pan();

縮放:自定義封裝Tool類實現ITool和ICommad接口

歷史視圖:自定義封裝Command類實現ICommand接口

書簽:調用ArcGIS組件類庫

注:ICommand實現命令,不需要與axMapControl交互;ITool需要與axMapControl交互,綁定了axMapControl的鍵盤、鼠標事件。

1.4.1 ICommand接口實現

以“前一視圖”為例,新建一個類繼承ICommand(ESRI.ArcGIS.SystemUI)接口,顯式實現接口,OnCreate(object Hook)傳入axMapControl控件Object屬性,OnClick()實現功能,歷史視圖是通過IActiveView.ExtentStack視圖堆棧實現的。

public void OnCreate(object Hook)
{
    hookHelper = new HookHelperClass();
    hookHelper.Hook = Hook;
    extentStack = hookHelper.ActiveView.ExtentStack;
    if (hookHelper.ActiveView == null)
        hookHelper = null;
}

public void OnClick()
{
    if (extentStack.CanUndo())
        extentStack.Undo();
    else
        enabled = false;
}

//調用
ICommand cmd = new ExtentBackCommand();
cmd.OnCreate(axMapControl.Object);
cmd.OnClick();

1.4.2 ITool接口實現

注:可以配合ICommand使用

放大功能

//鼠標指針樣式
public int Cursor
{
    get
    {
        ISystemMouseCursor pMouse = new SystemMouseCursorClass();
        pMouse.Load(esriSystemMouseCursor.esriSystemMouseCursorZoomIn);
        return pMouse.Cursor;
    }
}

public void OnMouseDown(int button, int shift, int x, int y)
{
    if (button == 2) return;
    //框選
    IEnvelope pEnv = mapControl.TrackRectangle();
    //點選
    if (pEnv.IsEmpty || pEnv.Width == 0 || pEnv.Height == 0)
    {
        pEnv = mapControl.Extent;
        pEnv.Expand(0.5, 0.5, true);
    }
    mapControl.Extent = pEnv;
    mapControl.Refresh();
}

//調用
ICommand tool = new MapZoomInTool();
tool.OnCreate(axMapControl.Object);
axMapControl.CurrentTool = tool as ITool;

1.4.3 組件庫類調用

"ControlXXXXX"(ESRI.ArcGIS.Controls)形式的類

1.4.4 視圖同步

用IDisplayTransformation裝axMapControl.Extent視圖,用IObjectCopy拷貝地圖

IActiveView pActiveView = (IActiveView)axPageLayoutControl.ActiveView.FocusMap;
IDisplayTransformation displayTransformation = pActiveView.ScreenDisplay.DisplayTransformation;
displayTransformation.VisibleBounds = axMapControl.Extent;
IObjectCopy pObjectCopy = new ObjectCopyClass();
object copyMap = pObjectCopy.Copy(axMapControl.Map);//復制地圖到copiedMap中
object copyToMap = axPageLayoutControl.ActiveView.FocusMap;
pObjectCopy.Overwrite(copyMap, ref copyToMap); //復制地圖

1.4.5 鼠標坐標

響應axMapControl_OnMouseMove事件

sMapUnits = BasicClass.GetMapUnit(axMapControl.Map.MapUnits);
statusBarLblCoor.Text = string.Format("{0:#.###} {1:#.###} {2}", e.mapX, e.mapY, sMapUnits);

其中地圖單位獲取(封裝在BasicClass內)

public static string GetMapUnit(esriUnits mapUnit)
{
    string sMapUnit = string.Empty;
    switch (mapUnit)
    {
        case esriUnits.esriCentimeters:
            sMapUnit = "厘米";
            break;
        case esriUnits.esriDecimalDegrees:
            sMapUnit = "十進制";
            break;
        case esriUnits.esriDecimeters:
            sMapUnit = "分米";
            break;
        case esriUnits.esriFeet:
            sMapUnit = "尺";
            break;
        case esriUnits.esriInches:
            sMapUnit = "英寸";
            break;
        case esriUnits.esriKilometers:
            sMapUnit = "千米";
            break;
        case esriUnits.esriMeters:
            sMapUnit = "米";
            break;
        case esriUnits.esriMiles:
            sMapUnit = "英里";
            break;
        case esriUnits.esriMillimeters:
            sMapUnit = "毫米";
            break;
        case esriUnits.esriNauticalMiles:
            sMapUnit = "海里";
            break;
        case esriUnits.esriPoints:
            sMapUnit = "點";
            break;
        case esriUnits.esriUnitsLast:
            sMapUnit = "UnitsLast";
            break;
        case esriUnits.esriUnknownUnits:
            sMapUnit = "未知單位";
            break;
        case esriUnits.esriYards:
            sMapUnit = "碼";
            break;
        default:
            sMapUnit = "未知單位";
            break;
    }
    return sMapUnit;
}

1.4.6 比例尺

實時顯示當前比例尺

響應axMapControl_OnAfterScreenDraw事件:menuCboMapScale.Text = string.Format("1:{0:#}", axMapControl.MapScale);

手動輸入比例尺

鍵盤代碼KeyValue請參考:CSDN:C# KeyValue列表

響應menuCboMapScale_KeyPress事件

if (e.KeyChar == 13)    //Enter
{
    bool isColon = menuCboMapScale.Text.Contains(":");
    if (isColon)
    {
        string[] strArray = menuCboMapScale.Text.Split(':');
        axMapControl.MapScale = double.Parse(strArray[1]);
    }
    else
        axMapControl.MapScale = double.Parse(menuCboMapScale.Text);
    axMapControl.Refresh();
}

國家標准比例尺

1:100,1:500,1:1000,1:2000,1:5000,1:1萬,1:2萬,1:5萬,1:10萬,1:25萬,1:50萬,1:100萬

響應menuCboMapScale_SelectedIndexChanged事件

string sMapScale = menuCboMapScale.SelectedItem.ToString();
string[] sArray = sMapScale.Split(':');//冒號分隔
axMapControl.MapScale = double.Parse(sArray[1].Trim(','));//去除逗號
axMapControl.Refresh();

1.5 圖層管理

1.5.1 右鍵菜單

添加contextMenuStrip控件,在axTOCControl的OnMouseDown事件內寫代碼

if (e.button == 2)//右鍵
{
    esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
    IBasicMap pBasicMap = null;
    object unk = null;
    object data = null;
    axTOCControl.HitTest(e.x, e.y, ref item, ref pBasicMap, ref pLyr, ref unk, ref data);
    if (item == esriTOCControlItem.esriTOCControlItemLayer)
    {
        if (pLyr is IFeatureLayer)  //矢量圖層
        {
            pFeaLyr = pLyr as IFeatureLayer;
            btnAttributeTable.Visible = true;
            btnLayerSelected.Visible = true;
            btnLayerSelectable.Visible = true;
            btnLayerUnSelectable.Visible = true;
            btnLayerOutput.Visible = true;
            btnLayerSelectable.Enabled = !pFeaLyr.Selectable;
            btnLayerUnSelectable.Enabled = pFeaLyr.Selectable;
            btnLayerSelected.Enabled = pFeaLyr.Selectable;
        }
        else  //柵格圖層
        {
            btnAttributeTable.Visible = false;
            btnLayerSelected.Visible = false;
            btnLayerSelectable.Visible = false;
            btnLayerUnSelectable.Visible = false;
            btnLayerOutput.Visible = false;
        }
        contextMenu.Show(Control.MousePosition);
    }
}

右鍵菜單

1.5.2 圖層定位

將圖層的“興趣區”賦值給地圖控件的視圖屬性,axMapControl.Extent = pFeaLyr.AreaOfInterest;

1.6 交互優化

軟件沒有數據時,一些功能是禁用的。

響應axMapControl_OnAfterScreenDraw事件:

//1 激活相關控件
//1.1 地圖瀏覽
bool isData = false;//存在數據?
isData = axMapControl.LayerCount > 0 ? true : false;
barMapBrowse.Enabled = isData;
//1.2 選擇查詢
barSelect.Enabled = isData;
//1.3 空間編輯
barEditor.Enabled = isData;
//1.4 歷史視圖
bool canUndo = axMapControl.ActiveView.ExtentStack.CanUndo();
btnExtentBack.Enabled = canUndo;
bool canRedo = axMapControl.ActiveView.ExtentStack.CanRedo();
btnExtentForward.Enabled = canRedo;

主界面圖標,響應FormMain_Load

//添加圖標
IntPtr Hicon = Properties.Resources.GenericGlobeLarge_B_16.GetHicon();
Icon newIcon = Icon.FromHandle(Hicon);
this.Icon = newIcon;

源碼鏈接:組件GIS


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM