PictureMarkerSymbolの集約


PictureMarkerSymbolなのにマルチレイヤって結構無駄なので集約する処理。
大体見えてる程度しか見てないが。

結局アプリ終了時処理とかにするか悩む。
作成時がベストではあるが…。

using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;


public class MxdUtil : IDisposable
{
  private IMapDocument m_mapDoc = null;
  private IMap m_map = null;

  public MxdUtil(string mxdpath, int index)
  {
    IMapDocument mapDoc = new MapDocumentClass();
    mapDoc.Open(mxdpath);

    var map = mapDoc.get_Map(index);

    this.m_map = map;
    this.m_mapDoc = mapDoc;
  }//end  method

  public void Test(string savePath)
  {
    using (ComReleaser com = new ComReleaser())
    {
      UID uid = new UIDClass();
      com.ManageLifetime(uid);

      uid.Value = "{" + typeof(IGeoFeatureLayer).GUID.ToString() + "}";

      var map = this.m_map;
      var enumLayers = map.get_Layers(uid, true);

      ILayer layer = null;

      while ((layer = enumLayers.Next()) != null)
      {
        this.setSymbols(layer);
      }//end loop

      var mapDoc = this.m_mapDoc;
      mapDoc.SaveAs(savePath, false, false);
    }
  }

  private void setSymbols(ILayer layer)
  {
    if (!(layer is IGeoFeatureLayer))
      return;

    IGeoFeatureLayer geoLayer = (IGeoFeatureLayer)layer;
    var render = geoLayer.Renderer;

    if (render is ISimpleRenderer)
    {
      var simple = (ISimpleRenderer)render;
      var sym = this.setSymbol(simple.Symbol);
      simple.Symbol = sym;
    }
    else if (render is IUniqueValueRenderer)
    {
      IUniqueValueRenderer unique = (IUniqueValueRenderer)render;
      for (int i = 0; i < unique.ValueCount; i++)
      {
        var val = unique.get_Value(i);
        var sym = this.setSymbol(unique.get_Symbol(val));
        unique.set_Symbol(val, sym);
      }//end loop
    }//end if

    //再セット
    geoLayer.Renderer = render;
  }//end method


  private ISymbol setSymbol(ISymbol symbol)
  {
    try
    {
      if (symbol is IMultiLayerMarkerSymbol &&
          ((IMultiLayerMarkerSymbol)symbol).LayerCount == 1)
      {
        var mm = (IMultiLayerMarkerSymbol)symbol;
        return (ISymbol)mm.get_Layer(0);
      }
      if (symbol is IMultiLayerLineSymbol &&
          ((IMultiLayerLineSymbol)symbol).LayerCount == 1)
      {
        var ml = (IMultiLayerLineSymbol)symbol;
        return (ISymbol)ml.get_Layer(0);
      }
      if (symbol is IMultiLayerFillSymbol &&
          ((IMultiLayerFillSymbol)symbol).LayerCount == 1)
      {
        var mf = (IMultiLayerFillSymbol)symbol;
        return (ISymbol)mf.get_Layer(0);
      }//end if

      if (!(symbol is IMultiLayerMarkerSymbol))
      {
        return symbol;
      }

      var markers = (IMultiLayerMarkerSymbol)symbol;
      bool hasPictureMarker = false;

      for (int i = 0; i < markers.LayerCount; i++)
      {
        var mark = markers.get_Layer(i);
        if (mark is IPictureMarkerSymbol)
          hasPictureMarker = true;
      }//end loop
      if (!hasPictureMarker)
        return symbol;

      string path = System.IO.Path.GetTempFileName();

      int width = 100,
          height = 100;


      using (ComReleaser com = new ComReleaser())
      using (Bitmap img = new Bitmap(width, height))
      using (Graphics g = Graphics.FromImage(img))
      {
        var hdc = g.GetHdc().ToInt32();

        IPoint pt = new PointClass();
        com.ManageLifetime(pt);
        pt.PutCoords(width / 2, height / 2);

        IPolygon gon = new PolygonClass();
        com.ManageLifetime(gon);

        symbol.SetupDC(hdc, null);
        symbol.QueryBoundary(hdc, null, pt, gon);

        if (gon == null || gon.IsEmpty ||
            gon.Envelope.Width == 0 ||
            gon.Envelope.Height == 0)
          return symbol;

        width = (int)Math.Ceiling(gon.Envelope.Width) + 1;
        height = (int)Math.Ceiling(gon.Envelope.Height) + 1;

        g.ReleaseHdc();
        symbol.ResetDC();
      }//end imges

      using (ComReleaser com = new ComReleaser())
      using (Bitmap img = new Bitmap(width, height))
      using (Graphics g = Graphics.FromImage(img))
      {
        var hdc = g.GetHdc().ToInt32();

        IPoint pt = new PointClass();
        com.ManageLifetime(pt);
        pt.PutCoords(width / 2, height / 2);

        symbol.SetupDC(hdc, null);
        symbol.Draw(pt);

        symbol.ResetDC();
        //変更適用
        g.ReleaseHdc();
        g.Dispose();

        img.Save(path, ImageFormat.Png);

        var mm = (IMultiLayerMarkerSymbol)symbol;
        IPictureMarkerSymbol pictSymbol = new PictureMarkerSymbolClass();
        pictSymbol.CreateMarkerSymbolFromFile(esriIPictureType.esriIPicturePNG, path);
        pictSymbol.Size = mm.Size;

        System.IO.File.Delete(path);

        return (ISymbol)pictSymbol;
      }
    }
    catch (Exception ex)
    {
      Debug.Print(ex.Message);
      Debug.Print(ex.StackTrace);
    }//end try

    return symbol;
  }

  public void Dispose()
  {
    if (this.m_mapDoc != null)
    {
      Marshal.FinalReleaseComObject(this.m_mapDoc);
      this.m_mapDoc = null;
    }
    if (this.m_map != null)
    {
      Marshal.FinalReleaseComObject(this.m_map);
      this.m_map = null;
    }//end if
  }//end method
}//end class
カテゴリー: 運用, 開発 タグ: パーマリンク

PictureMarkerSymbolの集約 への1件のフィードバック

  1. sakuzo より:

    この記事に関する内容ではないのですが、もしご存知でしたら教えて下さい。

    ArcMap(Ver.10.2.2 for desktop)のアドインをC#で開発しておりますが、
    Map.AddLayer()を実行すると例外も出ずにArcMapが突然終了(自殺)してしまいます。
    アドインの種別はExtensionです(ESRI.ArcGIS.Desktop.AddIns.Extension)。
    ちなみに、レイヤ生成のコード(=レイヤのオブジェクト)は問題ないことは保証出来ます。

    必ず自殺するわけではなく成功する時としない時があり、
    OpenDocument()やOnContextMenu()等の何かしらのMapイベントの中でAddLayer()すると成功し、
    自殺する時はこれらとは無関係な勝手なタイミングの時です(例:スレッド/タイマ/リモーティングからの呼び出し時)。

    今回はリモーティングで外部アプリからアドインを叩きレイヤを追加させたいのですが何かやりようはあるのでしょうか?(例えばMapのリフレッシュタイミングをフックする等)。
    スレッドモデル等が関連していると思われますがもし何かご存知でしたら教えて戴ければ幸いです。

    メールに直接戴いても構いません。
    宜しくお願い致します。

コメントは受け付けていません。