Engine地図移動動作を何とかしたい – 3 –



Engine地図移動動作を何とかしたい – 2 –

とりあえず2分割描画での見栄え?向上
初回のパンの挙動調整が残課題くらいか

使う側

public override void OnMouseDown(int button, int shift, int x, int y)
{
  if (m_hookHelper == null)
    return;

  if (this.m_Pan == null)
    this.m_Pan = new PanMng(this.m_hookHelper.FocusMap, this.m_hookHelper.PageLayout);

  this.m_Pan.PanStart(x, y);
}

public override void OnMouseMove(int button, int shift, int x, int y)
{
  if (this.m_hookHelper == null || this.m_Pan == null)
    return;

  this.m_Pan.PanMove(x, y);
}

public override void OnMouseUp(int button, int shift, int x, int y)
{
  if (this.m_hookHelper == null || this.m_Pan == null)
    return;

  this.m_Pan.PanStop(x, y);
  this.m_Pan = null;

}//end method

クラス実装

using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using esriGeom = ESRI.ArcGIS.Geometry;

/// <summary>
/// 地図移動管理
/// </summary>
public class PanMng
{
  //-------------------------
  #region WIN32 API
  //-------------------------

  /// <summary>
  /// ラスタ操作
  /// </summary>
  private enum TernaryRasterOperations : uint
  {
    /// <summary>dest = source</summary>
    SRCCOPY = 0x00CC0020,
    /// <summary>dest = source OR dest</summary>
    SRCPAINT = 0x00EE0086,
    /// <summary>dest = source AND dest</summary>
    SRCAND = 0x008800C6,
    /// <summary>dest = source XOR dest</summary>
    SRCINVERT = 0x00660046,
    /// <summary>dest = source AND (NOT dest)</summary>
    SRCERASE = 0x00440328,
    /// <summary>dest = (NOT source)</summary>
    NOTSRCCOPY = 0x00330008,
    /// <summary>dest = (NOT src) AND (NOT dest)</summary>
    NOTSRCERASE = 0x001100A6,
    /// <summary>dest = (source AND pattern)</summary>
    MERGECOPY = 0x00C000CA,
    /// <summary>dest = (NOT source) OR dest</summary>
    MERGEPAINT = 0x00BB0226,
    /// <summary>dest = pattern</summary>
    PATCOPY = 0x00F00021,
    /// <summary>dest = DPSnoo</summary>
    PATPAINT = 0x00FB0A09,
    /// <summary>dest = pattern XOR dest</summary>
    PATINVERT = 0x005A0049,
    /// <summary>dest = (NOT dest)</summary>
    DSTINVERT = 0x00550009,
    /// <summary>dest = BLACK</summary>
    BLACKNESS = 0x00000042,
    /// <summary>dest = WHITE</summary>
    WHITENESS = 0x00FF0062,
    /// <summary>
    /// Capture window as seen on screen.  This includes layered windows 
    /// such as WPF windows with AllowsTransparency="true"
    /// </summary>
    CAPTUREBLT = 0x40000000
  }

  [DllImport("gdi32.dll", SetLastError = true)]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

  //-------------------------
  #endregion WIN32 API
  //-------------------------

  private IMap m_Map = null;

  private IPageLayout m_PageLayout = null;

  private IScreenDisplay m_Display = null;

  private Point m_PanStartPoint = new Point();

  private Bitmap m_StartImg = null;

  private bool m_IsMoved = false;

  /// <summary>
  /// コンストラクタ
  /// </summary>
  /// <param name="map"></param>
  /// <param name="pageLayout"></param>
  public PanMng(IMap map, IPageLayout pageLayout)
  {
    this.m_Map = map;
    this.m_PageLayout = pageLayout;
    var actView = (IActiveView)map;
    this.m_Display = actView.ScreenDisplay;

  }//end method

  /// <summary>
  /// 移動開始
  /// </summary>
  /// <param name="x"></param>
  /// <param name="y"></param>
  public void PanStart(int x, int y)
  {
    this.m_PanStartPoint.X = x;
    this.m_PanStartPoint.Y = y;

    IScreenDisplay scDisplay = this.m_Display;
    var rect = scDisplay.DisplayTransformation.get_DeviceFrame();

    Bitmap bmp = new Bitmap(rect.right, rect.bottom);

    scDisplay.StartDrawing(scDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
    try
    {
      using (Graphics imgGraphics = Graphics.FromImage(bmp))
      {
        IntPtr screenGraphics = new IntPtr(scDisplay.hDC);
        IntPtr imgGr = imgGraphics.GetHdc();

        BitBlt(imgGr, 0, 0, bmp.Width, bmp.Height, screenGraphics, 0, 0, TernaryRasterOperations.SRCCOPY);

        imgGraphics.ReleaseHdc(imgGr);
      }
    }
    finally
    {
      scDisplay.FinishDrawing();
    }
    this.m_StartImg = bmp;
  }//end method

  /// <summary>
  /// 移動処理
  /// </summary>
  /// <param name="x"></param>
  /// <param name="y"></param>
  public void PanMove(int x, int y)
  {
    if (this.m_StartImg == null)
      return;
    IScreenDisplay scDisplay = this.m_Display;
    var rect = scDisplay.DisplayTransformation.get_DeviceFrame();

    scDisplay.StartDrawing(scDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
    try
    {
      IntPtr screenGraphics = new IntPtr(scDisplay.hDC);

      using (Graphics screen = Graphics.FromHdc(screenGraphics))
      using (SolidBrush solid = new SolidBrush(Color.White))
      using (Bitmap bmp = new Bitmap(rect.right, rect.bottom))
      using (Graphics backBuffer = Graphics.FromImage(bmp))
      {
        backBuffer.FillRectangle(solid, new Rectangle(rect.left, rect.top, rect.right, rect.bottom));
        Point imgPt = new Point();
        imgPt.X = x - this.m_PanStartPoint.X;
        imgPt.Y = y - this.m_PanStartPoint.Y;

        backBuffer.DrawImageUnscaled(this.m_StartImg, imgPt);
        backBuffer.Dispose();

        screen.DrawImageUnscaled(bmp, new Point(0, 0));
      }
    }
    finally
    {
      scDisplay.FinishDrawing();
    }//end try
  }//end method

  /// <summary>
  /// 移動停止
  /// </summary>
  /// <param name="x"></param>
  /// <param name="y"></param>
  public void PanStop(int x, int y)
  {
    using (ComReleaser com = new ComReleaser())
    {
      if (this.m_StartImg == null)
        return;

      try
      {
        var map = this.m_Map;
        var actView = (IActiveView)map;
        var scDisplay = actView.ScreenDisplay;

        var layers = new List<ILayer>();
        for (int i = 0; i < map.LayerCount; i++)
        {
          var layer = map.get_Layer(i);
          if (!layer.Visible)
            continue;

          layers.Add(layer);
        }//end loop

        for (int i = 0; i < layers.Count; i++)
        {
          if (i < layers.Count / 2)
            layers[i].Visible = false;
        }//end loop

        //scDisplay.StartRecording();
        //画像出力
        this.drawActiveViewToScreen(actView, scDisplay, x, y);
        //scDisplay.StopRecording();

        //確認用の3秒停止
        //Thread.Sleep(3 * 1000);

        foreach (var layer in layers)
        {
          layer.Visible = !layer.Visible;
        }//end loop

        var mapFrame = this.getMapFrameFromMap(map);
        var symbolBackGround = (ISymbolBackground)mapFrame.Background;
        var orgFillSymbol = symbolBackGround.FillSymbol;

        var simpleFill = new SimpleFillSymbolClass();
        com.ManageLifetime(simpleFill);
        var rgbColor = new RgbColorClass();
        com.ManageLifetime(rgbColor);
        rgbColor.Red = 255;
        rgbColor.Green = 255;
        rgbColor.Blue = 255;
        rgbColor.NullColor = true;
        rgbColor.Transparency = 0;

        simpleFill.Color = rgbColor;

        symbolBackGround.FillSymbol = simpleFill;
        mapFrame.Background = symbolBackGround;

        scDisplay.StartRecording();
        //画像出力
        this.drawActiveViewToScreen(actView, scDisplay, x, y);
        scDisplay.StartRecording();

        symbolBackGround.FillSymbol = orgFillSymbol;

        foreach (var layer in layers)
        {
          layer.Visible = true;
        }//end loop

        layers.Clear();
        layers = null;
      }
      finally
      {
        this.m_StartImg.Dispose();
        this.m_StartImg = null;
        this.m_IsMoved = false;
      }
    }//end com
  }//end method

  /// <summary>
  /// スクリーンにActiveViewの情報を反映
  /// </summary>
  /// <param name="actView"></param>
  /// <param name="scDisplay"></param>
  /// <param name="x"></param>
  /// <param name="y"></param>
  private void drawActiveViewToScreen(IActiveView actView, IScreenDisplay scDisplay, int x, int y)
  {
    var displayTransformation = scDisplay.DisplayTransformation;
    var rect = scDisplay.DisplayTransformation.get_DeviceFrame();

    using (ComReleaser com = new ComReleaser())
    {
      var env = actView.Extent;
      com.ManageLifetime(env);

      if (!this.m_IsMoved)
      {
        esriGeom.IPoint downPt = displayTransformation.ToMapPoint(this.m_PanStartPoint.X, this.m_PanStartPoint.Y);
        com.ManageLifetime(downPt);

        esriGeom.IPoint upPt = displayTransformation.ToMapPoint(x, y);
        com.ManageLifetime(upPt);

        esriGeom.ILine line = new esriGeom.LineClass();
        com.ManageLifetime(line);
        line.PutCoords(upPt, downPt);

        ((esriGeom.ITransform2D)env).MoveVector(line);
        actView.Extent = env;
        this.m_IsMoved = true;
      }
      var orgImg = this.m_StartImg;

      using (Bitmap img = new Bitmap(orgImg.Width, orgImg.Height))
      {
        scDisplay.StartDrawing(scDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
        try
        {
          using (Graphics g = Graphics.FromImage(img))
          {
            IntPtr ptr = g.GetHdc();
            actView.Output(ptr.ToInt32(), 96, ref rect, env, null);

            g.ReleaseHdc(ptr);
          }

          IntPtr screenGraphics = new IntPtr(scDisplay.hDC);

          using (Graphics screen = Graphics.FromHdc(screenGraphics))
          using (SolidBrush solid = new SolidBrush(Color.White))
          {
            //screen.FillRectangle(solid, new Rectangle(rect.left, rect.top, rect.right, rect.bottom));
            screen.DrawImageUnscaled(img, new Point(0, 0));
          }
        }
        finally
        {
          scDisplay.FinishDrawing();
        }

      }//end img

    }//end com
  }//ned method

  /// <summary>
  /// マップフレームの取得
  /// </summary>
  /// <param name="map"></param>
  /// <returns></returns>
  private IMapFrame getMapFrameFromMap(IMap map)
  {
    IGraphicsContainer page = (IGraphicsContainer)this.m_PageLayout;

    page.Reset();
    IElement elem = null;

    while ((elem = page.Next()) != null)
    {
      if (!(elem is IMapFrame))
        continue;

      IMapFrame mapFrame = (IMapFrame)elem;
      //名称一致
      if (mapFrame.Map.Name.Equals(map.Name))
        return mapFrame;
    }//end loop
    return null;
  }//end method

}//end class
カテゴリー: 開発 タグ: パーマリンク