程序編輯SHP文件並應用更改到數據源


在上一篇Blog中峻祁連介紹了在Map 3D中通過程序刪除圖層及數據源的方法,並且賣了個關子,這個方法還有另外一個妙用,今天就簡單介紹一下。對數據源的編輯估計是Map 3D開發中最常見的功能了,包括對添加、刪除和修改要素。這里以刪除要素為例介紹。下面的代碼實現了使用Map 3D API來刪除地圖上選中的要素。

 

    [CommandMethod("DeleteSelectedFeatures", CommandFlags.UsePickSet
          | CommandFlags.Modal | CommandFlags.Redraw)]
    public void DeleteSelectedFeatures()
    {
      Editor ed = Autodesk.AutoCAD.ApplicationServices
          .Application.DocumentManager.MdiActiveDocument.Editor;
      MgFeatureService _featureService = AcMapServiceFactory
        .GetService(MgServiceType.FeatureService) as MgFeatureService;
      PromptSelectionResult res = ed.SelectImplied();

      if (PromptStatus.OK == res.Status)
      {
        // Convert the SelectionSet to MgSelectionBase 
        // using AcMapFeatureEntityService. 

        Debug.Assert(res.Value != null);
        ObjectId entityID = res.Value[0].ObjectId;
        int entitytype = AcMapFeatureEntityService.GetEntityType(entityID);
        if (entitytype == EntityType.BulkEntity)
        {
          MgSelectionBase curSelection = AcMapFeatureEntityService
                                    .GetSelection(res.Value);

          foreach (MgLayerBase layer in curSelection.GetLayers())
          {
            string filter = curSelection
                  .GenerateFilter(layer, layer.FeatureClassName);

            if (filter != "")
            {
              MgFeatureCommandCollection featCommands =
                new MgFeatureCommandCollection();

              string strclassName = layer.FeatureClassName;
              MgDeleteFeatures delFeat =
                new MgDeleteFeatures(strclassName, filter);
              featCommands.Add(delFeat);
              try
              {
                AcMapLayer aclayer = layer as AcMapLayer;
                MgPropertyCollection pProps = aclayer
                  .UpdateFeatures(featCommands);

                // save and update the layer, commit the changes,
// 注意這里,必須要通過下面的代碼來checkin來應用對數據源的更改
MgFeatureQueryOptions opt = new MgFeatureQueryOptions(); // build the filter string, this is required for // data source such as Sql Server/Oracle... String commitFilter = ""; if (aclayer.IsCached() && EditMode.EditSet == aclayer.EditMode) { commitFilter = ClassSystemProperties.FeatureStatus + " = " + ClassSystemProperties.FeatureStatusDeleted; } opt.SetFilter(commitFilter); //This is a must aclayer.SaveFeatureChanges(opt); aclayer.ForceRefresh(); } catch (Autodesk.AutoCAD.Runtime.Exception ex) { ed.WriteMessage(ex.Message); } } } //remove the highlight AcMapFeatureEntityService.UnhighlightFeatures(curSelection); } } }

 

下面是執行時的截圖,首先用鼠標選中一些要素,然后執行自定義命令DeleteSelectedFeatures

image

執行結束后,選用的要素被成功刪除。

image

 

這個例子中我使用的FDO Provider for SHP連接到SHP文件。下面是上面自定義命令執行之前,注意一下shp相關文件的日期。

image

下面是DeleteSelectedFeatures執行完畢后,注意到Shp文件的相關變化,其中*.dbf文件是日期發在了變化,但*.shp文件並沒有變化。即上面的代碼並沒有對*.shp進行更改。

image

也許有人會說,這是個Map 3D的bug,他們的證據就是這時在ArcGIS中打開shp文件,發現剛才在Map 3D中刪除的要素還是ArcGIS中顯示,好像並沒有被刪除。其實不然。根據DBF規范,DBF保存屬性信息和刪除標志,SHP文件也采用了這個DBF規范。shp文件中被刪除的geometry只在DBF中做刪除標記。Map 3D的確對DBF文件做了更改,即按照規范添加了刪除標志。但不知道為什么ArcGIS並沒有遵守DBF規范,而忽略了該刪除標志,所以在ArcGIS查看時中你會認為該要素沒有刪除。下面是DBF規范相關點的摘錄:

http://www.dbf2002.com/dbf-file-format.html

Note   The data in dbf file starts at the position indicated in bytes 8 to 9 of the header record. Data records begin with a delete flag byte. If this byte is an ASCII space (0x20), the record is not deleted. If the first byte is an asterisk (0x2A), the record is deleted. The data from the fields named in the field subrecords follows the delete flag.

 

  盡管不是Map 3D的錯,但ArcGIS作為業內占統治地位的GIS軟件,我們也得遷就一下,有什么辦法在Map 3D中更改的結果也能讓ArcGIS顯示出來呢? 答案就是不但要按照DBF規范添加刪除標記,同時還要壓縮shp文件。目前在Map 3D中還沒有這樣的API來壓縮shp文件來反應要素變化,不過可以用下面的workaround,就是關閉到shp文件的連接(必要時再按照BuildMap中的例子再創建連接)。當FDO連接關閉時,Map 3D會壓縮shp文件,從而讓ArcGIS也能檢驗到變化。壓縮shp文件這個過程比較耗時,這也是Map 3D只是在關閉連接時才做這一步的原因。如果你要求你在Map 3D中的更改能更快的體現在ArcGIS中,就需要手動來關閉連接讓Map 3D強制壓縮shp。

關閉連接的代碼我們已經上一篇博客Map 3D中通過程序刪除圖層及數據源中介紹過了。這里還是把代碼貼一下:

    [CommandMethod("CloseConnection")]
    public void CloseConnectionForLayer()
    {
      RemoveLayer("Layer1");
    }

    public void RemoveLayer(string layerName)
    {
      Document doc = Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      Database db = doc.Database;

      AcMapMap map = AcMapMap.GetCurrentMap();

      // remove the layer
      var layers = map.GetLayers();
      if (!layers.Contains(layerName))
      {
        ed.WriteMessage("\nLayer does not exist: " + layerName);
        return;
      }

      MgLayerBase layer = layers.GetItem(layerName);
      layers.Remove(layer);

      // remove the layer resource
      MgResourceIdentifier identifier = layer.LayerDefinition;
      MgResourceService resourceService
        = AcMapServiceFactory.GetService(MgServiceType.ResourceService)
        as MgResourceService;

      if (resourceService.ResourceExists(identifier))
        resourceService.DeleteResource(identifier);

      // remove the feature source
      identifier = new MgResourceIdentifier(layer.FeatureSourceId);
      if (resourceService.ResourceExists(identifier))
        resourceService.DeleteResource(identifier);


    }
 

上面的代碼會從地圖中刪除圖層,並且關閉下圖中的DataConnection。

image

執行完畢,你會發現shp文件的日期已經反正了變化,這是在arcGIS中查看就可以看到修改后的效果了。

image

 

好了,希望對你有幫助。

 

還有更詳細的信息請同時看看這個http://adndevblog.typepad.com/infrastructure/2012/08/remove-the-discrepancy-between-arcviewarcgis-and-map-3d-when-deleting-features.html


免責聲明!

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



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