/// <summary>
/// グラフ表示画面
/// </summary>
/// <create>2010/01/26</create>
/// <modifier></modifier>
/// <modify></modify>
/// <modification></modification>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace lsor
{
    /// <summary><para>class outline:</para>
    /// <para>グラフ表示画面出力制御クラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[ver 1.0.0][2010/02/02][新規作成]</para>
    /// </remarks>
    public partial class GraphMain : Form
    {
        #region プライベートメンバ変数

        /// <summary>プロジェクト共通データ</summary>
        private CommonData _commonData;

        /// <summary>凡例ウィンドウ</summary>
        private GraphNotes legendWindow;

        /// <summary>ズーム機能のON/OFF</summary>
        private bool _bZoomFunction = false;

        // ズーム機能関連
        /// <summary>グラフ外枠</summary>
        private Rectangle _rectGraph = new Rectangle(-1, -1, -1, -1);
        /// <summary>ズーム矩形</summary>
        private RectangleF _rectZoom = new RectangleF(0.0F, 0.0F, 1.0F, 1.0F);
        /// <summary>ズーム履歴</summary>
        private List<RectangleF> _listZoomHistory = new List<RectangleF>();
        /// <summary>ズーム履歴のポインタ</summary>
        private int _indexZoomHistory = -1;
        /// <summary>ズーム機能の有効/無効</summary>
        private bool _bCapture = true;
        /// <summary>ズームの有無</summary>
        private bool _bZoom = false;
        /// <summary>ズーム状態の定義</summary>
        private enum ZoomState
        {
            NONE = 0,
            ZOOMIN,
            MOVE
        }
        /// <summary>ズーム状態</summary>
        private ZoomState _zoomState = ZoomState.NONE;

        /// <summary>座標定義</summary>
        private enum AXIS
        {
            X = 0,
            Y
        }

        /// <summary>マウスキャプチャフラグ</summary>
        private bool bHaveMouse = false;
        /// <summary>選択矩形の始点座標</summary>
        private Point ptOrigin = new Point(-1, -1);
        /// <summary>選択矩形の終点座標</summary>
        private Point ptCurrent = new Point(-1, -1);

// start of 印刷機能追加
        //印刷用・領域取得関数のインポート
        [System.Runtime.InteropServices.DllImport(@"C:\WINDOWS\system32\gdi32.dll")]
        private static extern int BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight,
                                         IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

        /// <summary>印刷用ビットマップ</summary>
        private Bitmap m_bit_img = null;//印刷用ビットマップ

        /// <summary>印刷用プリントドキュメント</summary>
        private System.Drawing.Printing.PrintDocument m_pd = null;
// end of 印刷機能追加

        #endregion

        #region コンストラクタ

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>GraphMain csGraphMain = new GraphMain(commonData)</para>
        /// </example>
        /// <param name="commonData">共通データ</param>
        /// <returns>グラフ表示画面出力制御クラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public GraphMain(CommonData commonData)
        {
            _commonData = commonData;
            if (_commonData == null)
            {
                _commonData = new CommonData();
            }

            InitializeComponent();

            if (pboxGraph.Image == null)
            {
                pboxGraph.Image = new Bitmap(2048, 2048);
            }
        }

        #endregion

        #region パブリックメソッド

        #region 共通データのセット

        /// <summary><para>method outline:</para>
        /// <para>共通データのセットをする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetCommonData(commonData)</para>
        /// </example>
        /// <param name="commonData">共通データ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetCommonData(CommonData commonData)
        {
            _commonData = commonData;
            if (legendWindow != null)
            {
                legendWindow.Close();
                legendWindow.SetCommonData(_commonData);
            }
            UpdateGraph(true);
        }

        #endregion

        #region グラフの更新

        /// <summary><para>method outline:</para>
        /// <para>グラフの更新をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>UpdateGraph(bInit)</para>
        /// </example>
        /// <param name="bInit">true:全データ再読み込み  false:グラフのみ更新</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void UpdateGraph(bool bInit)
        {
            try
            {
                if (bInit)
                {
                    _rectGraph.X = _rectGraph.Y = -1;
                    _zoomState = ZoomState.NONE;
                    _bZoom = false;
                    ResetZoomHistory();
                    UpdateZoomState();

                    string currentRiver = cboRiver.Text;

                    cboRiver.Items.Clear();
                    string[] river = Util.GetRiverNameList(_commonData);
                    if (river == null || river.Length <= 0)
                    {
                        // メッセージ:データファイルを読み込んでください。
                        MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_READ_DATA_FILE);
                        this.Close();
                        return;
                    }
                    int index = -1, index2 = -1;
                    for (int n = 0; n < river.Length; n++)
                    {
                        cboRiver.Items.Add(river[n]);
                        if (currentRiver != null && river[n] != null && currentRiver.Equals(river[n]))
                        {
                            index = n;
                        }
                        RiverData rd = Util.GetRiverData(_commonData, river[n]);
                        if (rd != null && rd.GraphPropList != null && rd.GraphPropList.Count > 0)
                        {
                            index2 = n;
                        }
                    }
                    if (index != -1)
                    {
                        cboRiver.SelectedIndex = index;
                    }
                    else if (index2 != -1)
                    {
                        cboRiver.SelectedIndex = index2;
                    }
                }

                if (pboxGraph.Image == null)
                {
                    pboxGraph.Image = new Bitmap(2048, 2048);
                }
                Graphics g = Graphics.FromImage(pboxGraph.Image);
                drawGraph(g);
                pboxGraph.Refresh();
                g.Dispose();

                if (legendWindow != null && !legendWindow.IsDisposed)
                {
                    legendWindow.SetCommonData(_commonData);
                    legendWindow.UpdateLegend(cboRiver.Text);
                }

                if (bInit)
                {
                    addZoomHistory();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Properties.HySAddinLsor2VieweEXEResources.CAPTION_WARNING, MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        #endregion

        #endregion

        #region プライベートメソッド

        #region データ系列設定メッセージの表示

        /// <summary><para>method outline:</para>
        /// <para>データ系列設定メッセージの表示をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>emptyMessage(g)</para>
        /// </example>
        /// <param name="g">描画エリア</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void emptyMessage(Graphics g)
        {
            Brush br = new SolidBrush(Color.Red);
            // メッセージ:河川名を選択し、データ系列を設定してください。
            g.DrawString(Properties.HySAddinLsor2VieweEXEResources.MSG_INFO_SELECT_RIVER_NAME_AND_SET_DATA_SERIES, this.Font, br, 20, 20);
            br.Dispose();
        }

        #endregion

        #region グラフ表示設定の初期化

        /// <summary><para>method outline:</para>
        /// <para>グラフ表示設定の初期化をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>GraphSettingData gs = defaultGraphSettingData()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>初期設定された表示設定</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private GraphSettingData defaultGraphSettingData()
        {
            GraphSettingData gs = new GraphSettingData();

            gs.Title = null;

            gs.X_ReverseFlg = false;
            gs.X_AutoScaleFlg = true;
            gs.X_MinValue = null;
            gs.X_MaxValue = null;
            gs.X_UnitDispFlg = false;
            gs.X_ValueDispFlg = true;
            gs.X_GridDispFlg = true;
            gs.X_SliceNoDispFlg = true;

            gs.YL_AutoScaleFlg = true;
            gs.YL_MaxValue = null;
            gs.YL_MinValue = null;
            gs.YL_UnitType = null;
            gs.YL_ValueDispFlg = true;
            gs.Y_GridDispFlg = true;

            gs.YR_AutoScaleFlg = true;
            gs.YR_MaxValue = null;
            gs.YR_MinValue = null;
            gs.YR_UnitType = null;
            gs.YR_ValueDispFlg = true;

            gs.InitializeFlg = false;

            return (gs);
        }
        #endregion

        #region グラフ描画用定数

        /// <summary>文字の高さ指標</summary>
        private const int CHAR_HEIGHT = 20;

        /// <summary>左余白</summary>
        private const int MARGIN_LEFT = 60;
        /// <summary>上余白</summary>
        private const int MARGIN_TOP = 40;
        /// <summary>右余白</summary>
        private const int MARGIN_RIGHT = 70;
        /// <summary>下余白</summary>
        private const int MARGIN_BOTTOM = 30;
        /// <summary>X軸とX軸数値の余白</summary>
        private const int MARGIN_XAXIS = 10;
        /// <summary>Y軸とY軸数値の余白</summary>
        private const int MARGIN_YAXIS = 5;
        /// <summary>X軸の目盛り分割の初期値(大きくするとより細かく区切る)</summary>
        private const int DIVIDE_X = 100;
        /// <summary>Y軸の目盛り分割の初期値(大きくするとより細かく区切る)</summary>
        private const int DIVIDE_Y = 50;
        /// <summary>Y軸の目盛り数値の文字高さ</summary>
        private const int YAXIS_INTERVAL = 20;
        /// <summary>断面Noの描画エリアの高さ</summary>
        private const int SECTION_HEIGHT = 60;
        /// <summary>断面Noの文字の高さ(幅)</summary>
        private const int SECTION_INTERVAL = 20;
        /// <summary>タイトルの上余白</summary>
        private const int TITLE_TOP = 20;

        #endregion

        #region グラフ描画矩形の算出

        /// <summary><para>method outline:</para>
        /// <para>グラフを描画する矩形(X軸/Y軸に囲まれた領域)の算出をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>Rectangle rect = calcGraphArea(gs)</para>
        /// </example>
        /// <param name="gs">グラフ表示設定</param>
        /// <returns>グラフ描画矩形</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private Rectangle calcGraphArea(GraphSettingData gs)
        {
            Rectangle rect = new Rectangle();

            // 現在のウィンドウサイズから各種余白を引いて計算
            rect.X = MARGIN_LEFT;
            rect.Width = pboxGraph.Width - MARGIN_LEFT - MARGIN_RIGHT;
            rect.Y = MARGIN_TOP;
            rect.Height = pboxGraph.Height - MARGIN_TOP - MARGIN_BOTTOM;
            if (gs.X_SliceNoDispFlg)
            {
                // 断面Noの表示ありの場合
                rect.Height -= SECTION_HEIGHT;
            }
            if (gs.X_ValueDispFlg)
            {
                // X軸数値の表示ありの場合
                rect.Height -= CHAR_HEIGHT;
            }
            if (gs.X_UnitDispFlg)
            {
                // X軸単位の表示ありの場合
                rect.Height -= CHAR_HEIGHT;
            }

            return (rect);
        }

        #endregion

        #region グラフ矩形の描画

        /// <summary><para>method outline:</para>
        /// <para>グラフの外枠矩形(X軸/Y軸)の描画をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawFrame(rect, g, pen)</para>
        /// </example>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィック</param>
        /// <param name="pen">ペン</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawFrame(Rectangle rect, Graphics g, Pen pen)
        {
            g.DrawRectangle(pen, rect);
        }

        #endregion

        #region グラフタイトルの描画

        /// <summary><para>method outline:</para>
        /// <para>グラフタイトルの描画をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawTitle(gs, rect, g, brush)</para>
        /// </example>
        /// <param name="gs">グラフ表示設定</param>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィック</param>
        /// <param name="brush">ブラシ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawTitle(GraphSettingData gs, Rectangle rect, Graphics g, SolidBrush brush)
        {
            if (!Util.IsBlank(gs.Title))
            {
                StringFormat sf = new StringFormat();
                sf.Alignment = StringAlignment.Center;
                sf.LineAlignment = StringAlignment.Near;

                g.DrawString(gs.Title, this.Font, brush, (rect.Left + rect.Right) / 2, TITLE_TOP, sf);

                sf.Dispose();
            }
        }

        #endregion

        #region 軸単位の描画

        /// <summary><para>method outline:</para>
        /// <para>グラフの軸単位の描画をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawUnit(gs, rect, g, brush)</para>
        /// </example>
        /// <param name="gs">グラフ表示設定</param>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィック</param>
        /// <param name="brush">ブラシ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawUnit(GraphSettingData gs, Rectangle rect, Graphics g, SolidBrush brush)
        {
            StringFormat sf = new StringFormat();

            // X軸単位
            if (gs.X_UnitDispFlg)
            {
                sf.Alignment = StringAlignment.Near;
                sf.LineAlignment = StringAlignment.Near;
                int bottom = rect.Bottom + 10;
                if (gs.X_ValueDispFlg)
                {
                    bottom += CHAR_HEIGHT;
                }
                g.DrawString("[m]", this.Font, brush, rect.Right, bottom, sf);
            }

            // Y軸左単位
            if (!Util.IsBlank(gs.YL_UnitType))
            {
                sf.Alignment = StringAlignment.Far;
                sf.LineAlignment = StringAlignment.Near;
                g.DrawString("[" + gs.YL_UnitType + "]", this.Font, brush, rect.Left, TITLE_TOP, sf);
            }

            // Y軸右単位
            if (!Util.IsBlank(gs.YR_UnitType))
            {
                sf.Alignment = StringAlignment.Near;
                sf.LineAlignment = StringAlignment.Near;
                g.DrawString("[" + gs.YR_UnitType + "]", this.Font, brush, rect.Right, TITLE_TOP, sf);
            }

            sf.Dispose();
        }

        #endregion

        #region データの最大値/最小値の取得

        /// <summary><para>method outline:</para>
        /// <para>データ配列を走査して最大値/最小値を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iData = parseData(data, min, max)</para>
        /// </example>
        /// <param name="data">データ配列</param>
        /// <param name="min">取得する最大値</param>
        /// <param name="max">取得する最小値</param>
        /// <returns>最大値/最小値</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int parseData(double?[] data, out double min, out double max)
        {
            int count = 0;
            min = 0;
            max = 0;
            if (data != null)
            {
                for (int i = 0; i < data.Length; i++)
                {
                    if (data[i] != null)
                    {
                        if (count == 0)
                        {
                            min = (double)data[i];
                            max = (double)data[i];
                        }
                        else
                        {
                            if (min > (double)data[i])
                            {
                                min = (double)data[i];
                            }
                            if (max < (double)data[i])
                            {
                                max = (double)data[i];
                            }
                        }
                        count++;
                    }
                }
            }

            if (count == 0)
            {
                min = 0;
                max = 0;
            }

            return (count);
        }

        #endregion

        #region 線分と矩形の交点計算

        /// <summary><para>method outline:</para>
        /// <para>2点で指定された線分が矩形と交わるかどうかを調べ、交わる場合は矩形でクリップした始点/終点を返す</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = clipRectAxis(rect, sx, sy, ex, ey)</para>
        /// </example>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="sx">線分の始点X座標</param>
        /// <param name="sy">線分の始点Y座標</param>
        /// <param name="ex">線分の終点X座標</param>
        /// <param name="ey">線分の終点Y座標</param>
        /// <returns>bool　true:交わる、false:交わらない</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool clipRectAxis(Rectangle rect, ref int sx, ref int sy, ref int ex, ref int ey)
        {
            Point ptS = new Point(sx, sy);
            Point ptE = new Point(ex, ey);
            Point ptRS = new Point(Math.Min(rect.X, rect.Right), Math.Min(rect.Y, rect.Bottom));
            Point ptRE = new Point(Math.Max(rect.X, rect.Right), Math.Max(rect.Y, rect.Bottom));

            // +------+------+------+
            // |      |      |      |
            // | 0101 | 0100 | 0110 |
            // |      |      |      |
            // +------+------+------+
            // |      |      |      |
            // | 0001 | 0000 | 0010 |
            // |      |      |      |
            // +------+------+------+
            // |      |      |      |
            // | 1001 | 1000 | 1010 |
            // |      |      |      |
            // +------+------+------+
            int sp = ((ptS.X < ptRS.X) ? 0x0001 : (ptS.X > ptRE.X) ? 0x0010 : 0x0000)
                   | ((ptS.Y < ptRS.Y) ? 0x0100 : (ptS.Y > ptRE.Y) ? 0x1000 : 0x0000);
            int ep = ((ptE.X < ptRS.X) ? 0x0001 : (ptE.X > ptRE.X) ? 0x0010 : 0x0000)
                   | ((ptE.Y < ptRS.Y) ? 0x0100 : (ptE.Y > ptRE.Y) ? 0x1000 : 0x0000);

            if (sp == 0 && ep == 0)
            {
                return (true);  // 両点包含
            }
            if ((sp & ep) != 0)
            {
                return (false); // 交点無し
            }
            if (sp != 0)
            {
                if (!getClipAxis(sp, ptRS, ptRE, ptS, ptE, ref ptS))
                {
                    return (false);
                }
                sx = ptS.X;
                sy = ptS.Y;
            }
            if (ep != 0)
            {
                if (!getClipAxis(ep, ptRS, ptRE, ptS, ptE, ref ptE))
                {
                    return (false);
                }
                ex = ptE.X;
                ey = ptE.Y;
            }

            return (true);
        }

        /// <summary><para>method outline:</para>
        /// <para>線分と矩形の交わりを調べる</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = getClipAxis(p, rs, re, s, e, n)</para>
        /// </example>
        /// <param name="p">エリアID</param>
        /// <param name="rs">矩形の始点座標</param>
        /// <param name="re">矩形の終点座標</param>
        /// <param name="s">線分の始点座標</param>
        /// <param name="e">線分の終点座標</param>
        /// <param name="n">矩形と線分の交点座標</param>
        /// <returns>bool　true:交わる、false:交わらない</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool getClipAxis(int p, Point rs, Point re, Point s, Point e, ref Point n)
        {
            if ((p & 0x0001) != 0)
            {
                if (getClipX(rs, re, s, e, rs.X, ref n))
                {
                    return (true);
                }
            }
            if ((p & 0x0010) != 0)
            {
                if (getClipX(rs, re, s, e, re.X, ref n))
                {
                    return (true);
                }
            }
            if ((p & 0x0100) != 0)
            {
                if (getClipY(rs, re, s, e, rs.Y, ref n))
                {
                    return (true);
                }
            }
            if ((p & 0x1000) != 0)
            {
                if (getClipY(rs, re, s, e, re.Y, ref n))
                {
                    return (true);
                }
            }

            return (false);
        }

        /// <summary><para>method outline:</para>
        /// <para>線分と矩形の交わりを調べる(縦辺)</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = getClipX(rs, re, s, e, x, n)</para>
        /// </example>
        /// <param name="rs">矩形の始点座標</param>
        /// <param name="re">矩形の終点座標</param>
        /// <param name="s">線分の始点座標</param>
        /// <param name="e">線分の終点座標</param>
        /// <param name="x">縦辺のX座標</param>
        /// <param name="n">矩形と線分の交点座標</param>
        /// <returns>bool　true:交わる、false:交わらない</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool getClipX(Point rs, Point re, Point s, Point e, int x, ref Point n)
        {
            int cy = (int)((double)(e.Y - s.Y) * (double)(x - s.X) / (double)(e.X - s.X) + (double)s.Y);
            if (cy < rs.Y || cy > re.Y)
            {
                return (false);
            }
            n.X = x;
            n.Y = cy;

            return (true);
        }

        /// <summary><para>method outline:</para>
        /// <para>線分と矩形の交わりを調べる(横辺)</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = getClipX(rs, re, s, e, y, n)</para>
        /// </example>
        /// <param name="rs">矩形の始点座標</param>
        /// <param name="re">矩形の終点座標</param>
        /// <param name="s">線分の始点座標</param>
        /// <param name="e">線分の終点座標</param>
        /// <param name="y">横辺のY座標</param>
        /// <param name="n">矩形と線分の交点座標</param>
        /// <returns>bool　true:交わる、false:交わらない</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool getClipY(Point rs, Point re, Point s, Point e, int y, ref Point n)
        {
            int cx = (int)((double)(e.X - s.X) * (double)(y - s.Y) / (double)(e.Y - s.Y) + (double)s.X);
            if (cx < rs.X || cx > re.X)
            {
                return (false);
            }
            n.X = cx;
            n.Y = y;

            return (true);
        }

        #endregion

        #region 座標が矩形内に含まれるかチェック

        /// <summary><para>method outline:</para>
        /// <para>座標が指定された矩形内に包含されているかチェックする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = inRect(rect, x, y)</para>
        /// </example>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="x">X座標</param>
        /// <param name="y">Y座標</param>
        /// <returns>bool　true:包含されている、false:包含されていない</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool inRect(Rectangle rect, int x, int y)
        {
            int sx = Math.Min(rect.X, rect.Right);
            int ex = Math.Max(rect.X, rect.Right);
            int sy = Math.Min(rect.Y, rect.Bottom);
            int ey = Math.Max(rect.Y, rect.Bottom);
            if (sx <= x && x <= ex && sy <= y && y <= ey)
            {
                return (true);
            }
            else
            {
                return (false);
            }
        }

        #endregion

        #region 描画座標の算出

        /// <summary><para>method outline:</para>
        /// <para>実データの値から画面への描画座標を算出する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int? iAxis = calcAxis(spix, epix, sval, eval, data, overflow)</para>
        /// </example>
        /// <param name="spix">画面座標の始点</param>
        /// <param name="epix">画面座標の終点</param>
        /// <param name="sval">始点の実データ値</param>
        /// <param name="eval">終点の実データ値</param>
        /// <param name="data">描画するデータ値</param>
        /// <param name="overflow">true:始点をはみ出ても計算  false:始点をはみ出たらnullを返す</param>
        /// <returns>描画座標</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int? calcAxis(int spix, int epix, double sval, double eval, double data, bool overflow)
        {
            int? axis = null;
            if (sval == data)
            {
                axis = spix;
            }
            else if (eval == data)
            {
                axis = epix;
            }
            else if (sval == eval)
            {
                axis = null;
            }
            else if (!overflow)
            {
                if (sval <= data && data <= eval)
                {
                    axis = (int)(spix + (double)(epix - spix) / (eval - sval) * (data - sval));
                }
                else if (sval >= data && data >= eval)
                {
                    axis = (int)(epix + (double)(spix - epix) / (sval - eval) * (data - eval));
                }
            }
            else
            {
                if (sval < eval)
                {
                    axis = (int)(spix + (double)(epix - spix) / (eval - sval) * (data - sval));
                }
                else if (sval > eval)
                {
                    axis = (int)(epix + (double)(spix - epix) / (sval - eval) * (data - eval));
                }
            }

            return (axis);
        }

        #endregion

        #region X座標データの取得

        /// <summary><para>method outline:</para>
        /// <para>X軸の座標データを共通データから取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>double?[] dAxisX = getAxisX(river, gs, count, min, max)</para>
        /// </example>
        /// <param name="river">河川名</param>
        /// <param name="gs">グラフ表示設定</param>
        /// <param name="count">データ数</param>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <returns>X軸の座標データ</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private double?[] getAxisX(string river, GraphSettingData gs, out int count, out double min, out double max)
        {
            // 累加距離の取得
            double?[] data = Util.GetDistanceData(_commonData, river);

            // 最小値・最大値の取得
            count = parseData(data, out min, out max);

            if (!gs.X_AutoScaleFlg)
            {
                // 自動スケールではない場合
                if (Util.IsDouble(gs.X_MinValue))
                {
                    min = Double.Parse(gs.X_MinValue);
                }
                if (Util.IsDouble(gs.X_MaxValue))
                {
                    max = Double.Parse(gs.X_MaxValue);
                }
            }
            if (gs.X_ReverseFlg)
            {
                // X軸逆転の場合
                if (min == max)
                {
                    min = max + 1;
                }
                else if (min < max)
                {
                    double tmp = max;
                    max = min;
                    min = tmp;
                }
            }
            else
            {
                // X軸を逆転しない場合
                if (min == max)
                {
                    max = min + 1;
                }
                else if (min > max)
                {
                    double tmp = min;
                    min = max;
                    max = tmp;
                }
            }

            // ズーム調整
            zoomScale(ref min, ref max, AXIS.X);

            return (data);
        }

        #endregion

        #region 最小値・最大値の調整

        /// <summary><para>method outline:</para>
        /// <para>自動スケールかどうかに応じて最小値・最大値を調整する(double?型版)</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ajustMinMaxValue(min, max, autoFlg, minStr, maxStr)</para>
        /// </example>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <param name="autoFlg">自動スケールフラグ</param>
        /// <param name="minStr">最小値文字列</param>
        /// <param name="maxStr">最大値文字列</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ajustMinMaxValue(ref double? min, ref double? max, bool autoFlg, string minStr, string maxStr)
        {
            if (!autoFlg)
            {
                // 自動スケールOFFの場合は文字列から設定
                if (Util.IsDouble(minStr))
                {
                    min = Double.Parse(minStr);
                }
                if (Util.IsDouble(maxStr))
                {
                    max = Double.Parse(maxStr);
                }
            }
            if (min == null || max == null)
            {
                // 最大・最小のいずれかが無効な場合は両方無効に
                min = max = null;
            }
            else if (min == max)
            {
                // 最大・最小が同じ場合はとりあえず1ずらす
                max = min + 1;
            }
            else if (min > max)
            {
                // 最小がminになるように入れ替え
                double? tmp = max;
                max = min;
                min = tmp;
            }
            if (autoFlg && min != null)
            {
                // 自動スケールがONの場合は上下に10%のマージンを持たせる。
                // データが上下限にピッタリつくと見苦しいので。
                // ただし原点(=0)をまたいでしまう場合は無理にマージンは設けない。
                double margin = ((double)max - (double)min) / 10.0;
                if (min >= 0.0 && min - margin < 0.0)
                {
                    min = 0.0;
                }
                else
                {
                    min -= margin;
                }
                if (max <= 0.0 && max + margin > 0.0)
                {
                    max = 0.0;
                }
                else
                {
                    max += margin;
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>自動スケールかどうかに応じて最小値・最大値を調整する(double型版)</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ajustMinMaxValue(min, max, autoFlg, minStr, maxStr)</para>
        /// </example>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <param name="autoFlg">自動スケールフラグ</param>
        /// <param name="minStr">最小値文字列</param>
        /// <param name="maxStr">最大値文字列</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ajustMinMaxValue(ref double min, ref double max, bool autoFlg, string minStr, string maxStr)
        {
            double? _min = min;
            double? _max = max;
            ajustMinMaxValue(ref _min, ref _max, autoFlg, minStr, maxStr);
            min = (double)_min;
            max = (double)_max;
        }

        #endregion

        #region ズームのスケール調整

        /// <summary><para>method outline:</para>
        /// <para>ズーム中の場合は指定された最大/最小値をズーム倍率に合わせて調整する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>zoomScale(minV, maxV, axis)</para>
        /// </example>
        /// <param name="minV">指定された最大値</param>
        /// <param name="maxV">指定された最小値</param>
        /// <param name="axis">座標定義</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void zoomScale(ref double? minV, ref double? maxV, AXIS axis)
        {
            if (minV != null && maxV != null)
            {
                double _min = (double)minV;
                double _max = (double)maxV;
                zoomScale(ref _min, ref _max, axis);
                minV = _min;
                maxV = _max;
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>ズーム中の場合は指定された最大/最小値をズーム倍率に合わせて調整する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>zoomScale(minV, maxV, axis)</para>
        /// </example>
        /// <param name="minV">指定された最大値</param>
        /// <param name="maxV">指定された最小値</param>
        /// <param name="axis">座標定義</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void zoomScale(ref double minV, ref double maxV, AXIS axis)
        {
            if (_bZoom)
            {
                double _s = (axis == AXIS.X) ? _rectZoom.X : _rectZoom.Y;
                double _e = (axis == AXIS.X) ? _rectZoom.Right : _rectZoom.Bottom;
                double _min, _max;
                _min = minV + (maxV - minV) * _s;
                _max = minV + (maxV - minV) * _e;
                minV = _min;
                maxV = _max;
            }
        }

        #endregion

        #region グラフデータ格納用クラス

        /// <summary><para>class outline:</para>
        /// <para>グラフデータ格納用クラス</para>
        /// </summary>
        /// <remarks><para>history:</para>
        /// <para>[ver 1.0.0][2010/02/02][新規作成]</para>
        /// </remarks>
        class GraphData
        {
            /// <summary>データ配列</summary>
            public double?[] data = null;
            /// <summary>最小値</summary>
            public double min = 0;
            /// <summary>最大値</summary>
            public double max = 0;
            /// <summary>データ数</summary>
            public int count = 0;
            /// <summary>データ系列設定</summary>
            public GraphPropData gp = null;
            /// <summary>描画フラグ</summary>
            public bool disp = false;

            /// <summary><para>method outline:</para>
            /// <para>コンストラクタ</para>
            /// </summary>
            /// <example><para>usage:</para>
            /// <para>GraphData csGraphData = new GraphData()</para>
            /// </example>
            /// <param name="">無し</param>
            /// <returns>グラフデータ格納用クラス</returns>
            /// <exception cref="">無し</exception>
            /// <remarks><para>remarks:</para>
            /// <para>無し</para>
            /// </remarks>
            public GraphData()
            {
            }
        }

        #endregion

        #region データ系列の取得

        /// <summary><para>method outline:</para>
        /// <para>グラフのデータ系列を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>GraphData[] csGraphDatas = getAxisY(river, rd, gs, minYL, maxYL, minYR, maxYR)</para>
        /// </example>
        /// <param name="river">河川名</param>
        /// <param name="rd">河川データ</param>
        /// <param name="gs">グラフ表示設定</param>
        /// <param name="minYL">Y軸左最小値</param>
        /// <param name="maxYL">Y軸左最大値</param>
        /// <param name="minYR">Y軸右最小値</param>
        /// <param name="maxYR">Y軸右最大値</param>
        /// <returns>グラフデータ</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private GraphData[] getAxisY(string river, RiverData rd, GraphSettingData gs, out double? minYL, out double? maxYL, out double? minYR, out double? maxYR)
        {
            minYL = null;
            maxYL = null;
            minYR = null;
            maxYR = null;

            // 入力パラメータのチェック
            if (Util.IsBlank(river) || rd == null || rd.GraphPropList == null || rd.GraphPropList.Count <= 0)
            {
                return (null);
            }

            // 格納メモリの確保
            GraphData[] dataArray = new GraphData[rd.GraphPropList.Count];

            // 河川のデータ系列分だけループ
            for (int n = 0; n < rd.GraphPropList.Count; n++)
            {
                // インスタンス生成
                dataArray[n] = new GraphData();
                // 描画設定の保存
                dataArray[n].gp = rd.GraphPropList[n];
                // 実データの取得
                dataArray[n].data = Util.GetCsvData(_commonData, river, dataArray[n].gp.FileId, dataArray[n].gp.ColumnNm);
                // 最大値・最小値の走査
                dataArray[n].count = parseData(dataArray[n].data, out dataArray[n].min, out dataArray[n].max);

                if (dataArray[n].count > 0 && (dataArray[n].gp.LineDisp || dataArray[n].gp.SymbolDisp))
                {
                    // 少なくとも1点は描画する場合
                    dataArray[n].disp = true;
                    if (dataArray[n].gp.ScaleType == (int)Util.SCALE.LeftY)
                    {
                        // スケールが「Y軸-左」の場合
                        if (minYL == null || (double)minYL > dataArray[n].min)
                        {
                            minYL = dataArray[n].min;
                        }
                        if (maxYL == null || (double)maxYL < dataArray[n].max)
                        {
                            maxYL = dataArray[n].max;
                        }
                    }
                    else if (dataArray[n].gp.ScaleType == (int)Util.SCALE.RightY)
                    {
                        // スケールが「Y軸-右」の場合
                        if (minYR == null || (double)minYR > dataArray[n].min)
                        {
                            minYR = dataArray[n].min;
                        }
                        if (maxYR == null || (double)maxYR < dataArray[n].max)
                        {
                            maxYR = dataArray[n].max;
                        }
                    }
                    else if (dataArray[n].gp.ScaleType == (int)Util.SCALE.Auto)
                    {
                        //スケールが「自動」の場合
                        ajustMinMaxValue(ref dataArray[n].min, ref dataArray[n].max, true, null, null);
                        zoomScale(ref dataArray[n].min, ref dataArray[n].max, AXIS.Y);
                    }
                }
            }

            // Y軸-左の最大値・最小値を調整
            ajustMinMaxValue(ref minYL, ref maxYL, gs.YL_AutoScaleFlg, gs.YL_MinValue, gs.YL_MaxValue);
            zoomScale(ref minYL, ref maxYL, AXIS.Y);

            // Y軸-右の最大値・最小値を調整
            ajustMinMaxValue(ref minYR, ref maxYR, gs.YR_AutoScaleFlg, gs.YR_MinValue, gs.YR_MaxValue);
            zoomScale(ref minYR, ref maxYR, AXIS.Y);

            // 調整したY軸の最大値・最小値を改めて各データにフィードバック
            for (int n = 0; n < dataArray.Length; n++)
            {
                if (dataArray[n].disp)
                {
                    if (dataArray[n].gp.ScaleType == (int)Util.SCALE.LeftY && minYL != null)
                    {
                        dataArray[n].min = (double)minYL;
                        dataArray[n].max = (double)maxYL;
                    }
                    else if (dataArray[n].gp.ScaleType == (int)Util.SCALE.RightY && minYR != null)
                    {
                        dataArray[n].min = (double)minYR;
                        dataArray[n].max = (double)maxYR;
                    }
                }
            }

            return (dataArray);
        }

        #endregion

        #region 軸の目盛間隔の丸め

        /// <summary><para>method outline:</para>
        /// <para>指定された数値を 1, 2, 5 の切りの良い数値に丸める(切り上げ)</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>double dGrid = roundGrid(interval)</para>
        /// </example>
        /// <param name="interval">数値</param>
        /// <returns>丸めた数値</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private double roundGrid(double interval)
        {
            double factor = 1.0;

            while (true)
            {
                if (interval <= 1.0 && interval > 0.5)
                {
                    return (1.0 * factor);
                }
                else if (interval <= 0.5 && interval > 0.2)
                {
                    return (0.5 * factor);
                }
                else if (interval <= 0.2 && interval > 0.1)
                {
                    return (0.2 * factor);
                }

                if (interval > 1.0)
                {
                    factor *= 10.0;
                    interval /= 10.0;
                }
                else
                {
                    factor /= 10.0;
                    interval *= 10.0;
                }
            }
        }

        #endregion

        #region X軸目盛り描画のサブルーチン

        /// <summary><para>method outline:</para>
        /// <para>X軸目盛りを描画する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawAxisXSub(g, pen, brush, rect, min, max, v, interval, dispValue, dispGrid)</para>
        /// </example>
        /// <param name="g">グラフィック</param>
        /// <param name="pen">ペン</param>
        /// <param name="brush">ブラシ</param>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <param name="v">データ値</param>
        /// <param name="interval">目盛り間隔</param>
        /// <param name="dispValue">数値描画フラグ</param>
        /// <param name="dispGrid">グリッド描画フラグ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawAxisXSub(Graphics g, Pen pen, SolidBrush brush, Rectangle rect, double min, double max, double v, double interval, bool dispValue, bool dispGrid)
        {
            // 描画座標の算出
            int? x = calcAxis(rect.Left, rect.Right, min, max, v, false);
            if (x == null)
            {
                return;
            }

            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Near;

            Pen pen2 = new Pen(Color.Blue, 1);
            pen2.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;

            // 目盛り10本おきに数値とグリッドを描画する
            interval *= 10.0;
            if (Math.Abs((v / interval) - Math.Round(v / interval)) < 0.001)
            {
                // 目盛り線(長め)の描画
                g.DrawLine(pen, (int)x, rect.Bottom, (int)x, rect.Bottom + 4);
                if (dispValue)
                {
                    // 目盛り数値の描画
                    g.DrawString(v.ToString(), this.Font, brush, (int)x, rect.Bottom + MARGIN_XAXIS, sf);
                }
                if (dispGrid && v != min && v != max)
                {
                    // グリッドの描画
                    g.DrawLine(pen2, (int)x, rect.Top, (int)x, rect.Bottom);
                }
            }
            else
            {
                // 目盛り線(短め)の描画
                g.DrawLine(pen, (int)x, rect.Bottom, (int)x, rect.Bottom + 2);
            }

            pen2.Dispose();
            sf.Dispose();
        }

        #endregion

        #region X軸目盛りの描画

        /// <summary><para>method outline:</para>
        /// <para>X軸の目盛りを描画する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawAxisX(gs, rect, g, pen, brush, min, max)</para>
        /// </example>
        /// <param name="gs">グラフ表示設定</param>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィックス</param>
        /// <param name="pen">ペン</param>
        /// <param name="brush">ブラシ</param>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawAxisX(GraphSettingData gs, Rectangle rect, Graphics g, Pen pen, SolidBrush brush, double min, double max)
        {
            if (min == max)
            {
                // 最大値=最小値の場合はセンターに1本だけ目盛りを表示(通常はあり得ない)
                int x = (rect.Left + rect.Right) / 2;
                g.DrawLine(pen, x, rect.Bottom, x, rect.Bottom + 4);
                if (gs.X_ValueDispFlg)
                {
                    StringFormat sf = new StringFormat();
                    sf.Alignment = StringAlignment.Center;
                    sf.LineAlignment = StringAlignment.Near;
                    g.DrawString(min.ToString(), this.Font, brush, x, rect.Bottom + MARGIN_XAXIS, sf);
                    sf.Dispose();
                }
            }
            else
            {
                // 一旦 DIVIDE_X で割って暫定の目盛り間隔を計算
                double interval = Math.Abs(min - max) / DIVIDE_X;
                // 1,2,5 の切れの良い数値に丸める
                interval = roundGrid(interval);

                if (min < max)
                {
                    // 左が原点の場合
                    int n = 0;
                    double v;
                    while (true)
                    {
                        // 目盛りを一つずつ進める
                        v = (Math.Ceiling(min / interval) + n) * interval;
                        if (v > max)
                        {
                            break;
                        }
                        // 目盛りの描画
                        drawAxisXSub(g, pen, brush, rect, min, max, v, interval, gs.X_ValueDispFlg, gs.X_GridDispFlg);
                        n++;
                    }
                }
                else
                {
                    // 右が原点の場合
                    int n = 0;
                    double v;
                    while (true)
                    {
                        // 目盛りを一つずつ戻す
                        v = (Math.Floor(min / interval) - n) * interval;
                        if (v < max)
                        {
                            break;
                        }
                        // 目盛りの描画
                        drawAxisXSub(g, pen, brush, rect, min, max, v, interval, gs.X_ValueDispFlg, gs.X_GridDispFlg);
                        n++;
                    }
                }
            }
        }

        #endregion

        #region Y軸目盛りの描画

        /// <summary>
        /// Y軸の目盛りを描画する
        /// </summary>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィックス</param>
        /// <param name="pen">ペン</param>
        /// <param name="brush">ブラシ</param>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <param name="dispValue">数値描画フラグ</param>
        /// <param name="dispGrid">グリッド描画フラグ</param>
        /// <param name="left">true:Y軸-左  false:Y軸-右</param>
        private void drawAxisY(Rectangle rect, Graphics g, Pen pen, SolidBrush brush, double? min, double? max, bool dispValue, bool dispGrid, bool left)
        {
            // 最小値か最大値がnullの場合は描画しない
            if (min == null || max == null)
            {
                return;
            }

            StringFormat sf = new StringFormat();
            sf.Alignment = left ? StringAlignment.Far : StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Center;
            // Y軸のX座標
            int x0 = left ? rect.Left : rect.Right;
            // 短い目盛りの始点X座標
            int x1 = left ? rect.Left - 2 : rect.Right + 2;
            // 長い目盛りの始点X座標
            int x2 = left ? rect.Left - 4 : rect.Right + 4;
            // 目盛り数値の始点X座標
            int x3 = left ? rect.Left - MARGIN_YAXIS : rect.Right + MARGIN_YAXIS;

            // グリッド用ペン
            Pen pen2 = new Pen(Color.Blue, 1);
            pen2.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;

            if (min == max)
            {
                // 最小値=最大値の場合は中心に1本だけ目盛りを引く(通常はあり得ない)
                int y = (rect.Top + rect.Bottom) / 2;
                g.DrawLine(pen, x0, y, x2, y);
                if (dispValue)
                {
                    g.DrawString(min.ToString(), this.Font, brush, x3, y, sf);
                }
            }
            else
            {
                // 一旦 DIVIDE_Y で割って暫定の目盛り間隔を計算
                double interval = Math.Abs((double)min - (double)max) / DIVIDE_Y;
                // 1,2,5 の切れの良い数値に丸める
                interval = roundGrid(interval);

                int n = 0;
                double v;
                while (true)
                {
                    // 下から順に目盛りを描画していく
                    v = (Math.Ceiling((double)min / interval) + n) * interval;
                    if (v > max)
                    {
                        break;
                    }
                    // 目盛りのY座標を計算
                    int? y = calcAxis(rect.Bottom, rect.Top, (double)min, (double)max, v, false);
                    if (y != null)
                    {
                        // 5本ごとに目盛り数値を描画する
                        if (Math.Abs((v / (interval * 5.0)) - Math.Round(v / (interval * 5.0))) < 0.001)
                        {
                            // 目盛り線(長め)の描画
                            g.DrawLine(pen, x0, (int)y, x2, (int)y);
                            if (dispValue)
                            {
                                // 目盛り数値の描画
                                g.DrawString(v.ToString(), this.Font, brush, x3, (int)y, sf);
                            }
                            if (dispGrid && v != min && v != max)
                            {
                                // グリッド線の描画
                                g.DrawLine(pen2, rect.Left, (int)y, rect.Right, (int)y);
                            }
                        }
                        else
                        {
                            // 目盛り線(短め)の描画
                            g.DrawLine(pen, x0, (int)y, x1, (int)y);
                        }
                    }
                    n++;
                }
            }

            sf.Dispose();
            pen2.Dispose();
        }

        #endregion

        #region データ線の描画

        /// <summary><para>method outline:</para>
        /// <para>グラフのデータ線を1本描画する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawData(rect, g, dataX, minX, maxX, dataY, minY, maxY, gp)</para>
        /// </example>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィックス</param>
        /// <param name="dataX">X軸データ</param>
        /// <param name="minX">X軸最小値</param>
        /// <param name="maxX">X軸最大値</param>
        /// <param name="dataY">グラフデータ</param>
        /// <param name="minY">Y軸の最小値</param>
        /// <param name="maxY">Y軸の最大値</param>
        /// <param name="gp">グラフ描画設定</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawData(Rectangle rect, Graphics g, double?[] dataX, double? minX, double? maxX, double?[] dataY, double minY, double maxY, GraphPropData gp)
        {
            // パラメータのチェック
            if (dataX == null || dataX.Length <= 0 || dataY == null || dataY.Length <= 0 || minX == null || maxX == null)
            {
                return;
            }
            // X軸の個数とデータの個数が合ってない!!(通常はあり得ない)
            if (dataX.Length != dataY.Length)
            {
                Console.WriteLine("dataX.Length != dataY.Length");
                return;
            }

            // グラフ描画矩形からはみ出ないようにクリップ
            g.SetClip(rect);

            Pen pen = null;
            Pen pen2 = null;
            Brush brush = null;
            int wid = 0;

            // 線表示がONの場合
            if (gp.LineDisp)
            {
                // 描画用のペン生成
                pen = new Pen(System.Drawing.Color.FromArgb(gp.LineColor));
                // 線種の設定
                switch (gp.LineType)
                {
                    case (int)Util.LINESTYLE.Dot: pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; break;
                    case (int)Util.LINESTYLE.Dash: pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; break;
                    case (int)Util.LINESTYLE.DashDot: pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot; break;
                    case (int)Util.LINESTYLE.DashDotDot: pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDotDot; break;
                    default: pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; break;
                }
                // 太さの設定
                switch (gp.LineSize)
                {
                    case (int)Util.LINEWIDTH.Thin: pen.Width = 1; break;
                    case (int)Util.LINEWIDTH.Middle: pen.Width = 2; break;
                    case (int)Util.LINEWIDTH.Thick: pen.Width = 4; break;
                    default: pen.Width = 1; break;
                }
            }
            // シンボル表示がONの場合
            if (gp.SymbolDisp)
            {
                // シンボル描画用のペン生成
                pen2 = new Pen(System.Drawing.Color.FromArgb(gp.SymbolColor));
                pen2.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
                pen2.Width = 1;

                // シンボル塗りつぶし用のブラシ生成
                brush = new SolidBrush(System.Drawing.Color.FromArgb(gp.SymbolColor));

                // シンボルサイズ
                switch (gp.SymbolSize)
                {
                    case (int)Util.SYMBOLSIZE.Small: wid = 6; break;
                    case (int)Util.SYMBOLSIZE.Medium: wid = 8; break;
                    case (int)Util.SYMBOLSIZE.Large: wid = 10; break;
                    default: wid = 6; break;
                }
            }

            // 1個前の点と現在の点を結んでいく
            int? preX = null;
            int? preY = null;
            for (int idx = 0; idx < dataX.Length; idx++)
            {
                int? curX = null;
                int? curY = null;
                if (dataX[idx] != null && dataY[idx] != null)
                {
                    // 描画X座標を取得
                    curX = calcAxis(rect.Left, rect.Right, (double)minX, (double)maxX, (double)dataX[idx], true);
                    // 描画Y座標を取得
                    curY = calcAxis(rect.Bottom, rect.Top, minY, maxY, (double)dataY[idx], true);
                    if (gp.LineDisp && curX != null && curY != null && preX != null && preY != null)
                    {
                        int sx = (int)curX;
                        int sy = (int)curY;
                        int ex = (int)preX;
                        int ey = (int)preY;
                        if (clipRectAxis(rect, ref sx, ref sy, ref ex, ref ey))
                        {
                            // ラインを描画
                            g.DrawLine(pen, sx, sy, ex, ey);
                        }
                    }
                }
                preX = curX;
                preY = curY;
            }

            // ラインと重ならないようにシンボルを描画するため、ラインとは分けて改めてシンボルを描画
            for (int idx = 0; idx < dataX.Length; idx++)
            {
                int? curX = null;
                int? curY = null;
                if (dataX[idx] != null && dataY[idx] != null)
                {
                    // 描画X座標を取得
                    curX = calcAxis(rect.Left, rect.Right, (double)minX, (double)maxX, (double)dataX[idx], true);
                    // 描画Y座標を取得
                    curY = calcAxis(rect.Bottom, rect.Top, minY, maxY, (double)dataY[idx], true);
                    if (gp.SymbolDisp
                        && curX != null && curY != null
                        && inRect(rect, (int)curX, (int)curY))
                    {
                        // シンボル描画用の座標を計算
                        //
                        //  sy +---+---+
                        //     |   |   |
                        //  cy +---+---+
                        //     |   |   |
                        //  ey +---+---+
                        //     sx  cx  ex
                        //
                        int sx = (int)curX - wid / 2;
                        int ex = (int)curX + wid / 2;
                        int cx = (int)curX;
                        int sy = (int)curY - wid / 2;
                        int ey = (int)curY + wid / 2;
                        int cy = (int)curY;

                        // シンボル形状に応じてマークを描画
                        switch (gp.SymbolType)
                        {
                            case (int)Util.SYMBOLSTYLE.Cross:       // ＋
                                g.DrawLine(pen2, cx, sy, cx, ey);
                                g.DrawLine(pen2, sx, cy, ex, cy);
                                break;
                            case (int)Util.SYMBOLSTYLE.Cross2:      // ×
                                g.DrawLine(pen2, sx, sy, ex, ey);
                                g.DrawLine(pen2, ex, sy, sx, ey);
                                break;
                            case (int)Util.SYMBOLSTYLE.Circle:      // ○
                                g.DrawEllipse(pen2, sx, sy, wid, wid);
                                break;
                            case (int)Util.SYMBOLSTYLE.CircleF:     // ●
                                g.FillEllipse(brush, sx, sy, wid, wid);
                                break;
                            case (int)Util.SYMBOLSTYLE.Triangle:    // △
                                Point[] p1 = { new Point(cx, sy), new Point(sx, ey), new Point(ex, ey) };
                                g.DrawPolygon(pen2, p1);
                                break;
                            case (int)Util.SYMBOLSTYLE.TriangleF:   // ▲
                                Point[] p2 = { new Point(cx, sy), new Point(sx, ey), new Point(ex, ey) };
                                g.FillPolygon(brush, p2);
                                break;
                            case (int)Util.SYMBOLSTYLE.Triangle2:   // ▽
                                Point[] p3 = { new Point(sx, sy), new Point(ex, sy), new Point(cx, ey) };
                                g.DrawPolygon(pen2, p3);
                                break;
                            case (int)Util.SYMBOLSTYLE.Triangle2F:  // ▼
                                Point[] p4 = { new Point(sx, sy), new Point(ex, sy), new Point(cx, ey) };
                                g.FillPolygon(brush, p4);
                                break;
                            case (int)Util.SYMBOLSTYLE.Square:      // □
                                g.DrawRectangle(pen2, sx, sy, wid, wid);
                                break;
                            case (int)Util.SYMBOLSTYLE.SquareF:     // ■
                                g.FillRectangle(brush, sx, sy, wid, wid);
                                break;
                            case (int)Util.SYMBOLSTYLE.Square2:     // ◇
                                Point[] p5 = { new Point(cx, sy), new Point(ex, cy), new Point(cx, ey), new Point(sx, cy) };
                                g.DrawPolygon(pen2, p5);
                                break;
                            case (int)Util.SYMBOLSTYLE.Square2F:    // ◆
                                Point[] p6 = { new Point(cx, sy), new Point(ex, cy), new Point(cx, ey), new Point(sx, cy) };
                                g.FillPolygon(brush, p6);
                                break;
                            default:        // ×
                                g.DrawLine(pen2, sx, sy, ex, ey);
                                g.DrawLine(pen2, ex, sy, sx, ey);
                                break;
                        }
                    }
                }
            }

            if (pen != null)
            {
                pen.Dispose();
            }
            if (pen2 != null)
            {
                pen2.Dispose();
            }
            if (brush != null)
            {
                brush.Dispose();
            }
            g.ResetClip();
        }

        #endregion

        #region 断面Noの描画

        /// <summary><para>method outline:</para>
        /// <para>X軸の下に断面Noを描画する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawSectionNo(gs, rect, g, pen, brush, distance, section, min, max)</para>
        /// </example>
        /// <param name="gs">グラフ表示設定</param>
        /// <param name="rect">グラフ描画矩形</param>
        /// <param name="g">グラフィックス</param>
        /// <param name="pen">ペン</param>
        /// <param name="brush">ブラシ</param>
        /// <param name="distance">累加距離配列</param>
        /// <param name="section">断面No配列</param>
        /// <param name="min">X軸最小値</param>
        /// <param name="max">X軸最大値</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawSectionNo(GraphSettingData gs, Rectangle rect, Graphics g, Pen pen, SolidBrush brush, double?[] distance, string[] section, double min, double max)
        {
            if (!gs.X_SliceNoDispFlg)
            {
                // 断面Noを表示しない場合
                return;
            }

            // 断面Noの描画Y座標を計算
            int bottom = rect.Bottom + 10;
            if (gs.X_ValueDispFlg)
            {
                // X軸の数値表示がある場合は少し下に下げる
                bottom += CHAR_HEIGHT;
            }
            if (gs.X_UnitDispFlg)
            {
                // X軸の単位表示がある場合は少し下に下げる
                bottom += CHAR_HEIGHT;
            }
            bottom += 5;

            // 断面No用の水平線を描画
            g.DrawLine(pen, rect.Left, bottom, rect.Right, bottom);
            // 左端の目盛り線を描画
            g.DrawLine(pen, rect.Left, bottom, rect.Left, bottom - 5);
            // 右端の目盛り線を描画
            g.DrawLine(pen, rect.Right, bottom, rect.Right, bottom - 5);

            if (distance == null || section == null)
            {
                return;
            }

            // 前回の断面No描画X座標を preX とする
            // 必ず1回目は描画するような適当な値で初期化
            int preX;
            if (min <= max)
            {
                preX = rect.Left - SECTION_INTERVAL * 2;
            }
            else
            {
                preX = rect.Right + SECTION_INTERVAL * 2;
            }

            // 縦書きにする
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Far;
            sf.LineAlignment = StringAlignment.Center;

            for (int i = 0; i < distance.Length; i++)
            {
                if (distance[i] != null && !Util.IsBlank(section[i]))
                {
                    // 描画のX座標を計算
                    int? x = calcAxis(rect.Left, rect.Right, min, max, (double)distance[i], false);
                    if (x != null)
                    {
                        // 前回描画した座標と一定間隔以上離れていたら描画
                        // くっついていたら描画せずにスキップ
                        // 隣り合う断面Noの文字が重ならないように配慮
                        if (Math.Abs((int)x - preX) > SECTION_INTERVAL)
                        {
                            preX = (int)x;

                            // 目盛り線の描画
                            g.DrawLine(pen, (int)x, bottom, (int)x, bottom + 2);
                            // 断面No文字の描画
                            int y = bottom + 3;
                            // アフィン変換して縦書き
                            g.TranslateTransform((int)x - y, (int)x + y);
                            g.RotateTransform(270F);
                            g.DrawString(section[i], this.Font, brush, (int)x, bottom + 3, sf);
                            g.ResetTransform();
                        }
                    }
                }
            }
        }

        #endregion

        #region グラフの描画メイン処理

        /// <summary><para>method outline:</para>
        /// <para>グラフ描画のメイン処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawGraph(g)</para>
        /// </example>
        /// <param name="g">グラフィックス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawGraph(Graphics g)
        {
            // 画像のクリア
            g.Clear(Color.White);

            // 河川データのチェック
            string river = cboRiver.Text;
            if (river == null || river.Length <= 0)
            {
                emptyMessage(g);
                return;
            }

            // データ系列のチェック
            RiverData rd = Util.GetRiverData(_commonData, river);
            if (rd == null || rd.GraphPropList == null || rd.GraphPropList.Count <= 0)
            {
                emptyMessage(g);
                return;
            }

            // 表示設定の取得
            GraphSettingData gs = rd.GraphSettingData;
            if (gs == null || !gs.InitializeFlg)
            {
                gs = defaultGraphSettingData();
            }

            // 描画用オブジェクト
            Pen defPen = new Pen(Color.Black);
            SolidBrush defBrush = new SolidBrush(Color.Black);

            // グラフ矩形の算出
            _rectGraph = calcGraphArea(gs);

            // タイトルの描画
            drawTitle(gs, _rectGraph, g, defBrush);

            // 単位の描画
            drawUnit(gs, _rectGraph, g, defBrush);

            // X軸データの取得
            int countX;
            double minX, maxX;
            double?[] dataX = getAxisX(river, gs, out countX, out minX, out maxX);

            // X軸の描画
            drawAxisX(gs, _rectGraph, g, defPen, defBrush, minX, maxX);

            // Y軸データの取得
            double? minYL, maxYL, minYR, maxYR;
            GraphData[] dataY = getAxisY(river, rd, gs, out minYL, out maxYL, out minYR, out maxYR);

            // Y軸の描画
            drawAxisY(_rectGraph, g, defPen, defBrush, minYL, maxYL, gs.YL_ValueDispFlg, gs.Y_GridDispFlg, true);
            drawAxisY(_rectGraph, g, defPen, defBrush, minYR, maxYR, gs.YR_ValueDispFlg, false, false);

            // グラフの描画
            for (int n = 0; dataY != null && n < dataY.Length; n++)
            {
                if (dataY[n].disp)
                {
                    drawData(_rectGraph, g, dataX, minX, maxX, dataY[n].data, dataY[n].min, dataY[n].max, dataY[n].gp);
                }
            }

            // 断面Noの描画
            if (gs.X_SliceNoDispFlg)
            {
                // 断面Noの取得
                string[] section = Util.GetSectionNo(_commonData, river);
                drawSectionNo(gs, _rectGraph, g, defPen, defBrush, dataX, section, minX, maxX);
            }

            // 枠の描画
            drawFrame(_rectGraph, g, defPen);

            defPen.Dispose();
            defBrush.Dispose();
        }

        #endregion

        #region テキストファイルの保存

        /// <summary><para>method outline:</para>
        /// <para>指定されたtextをfileNameに保存する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>saveCsvData(fileName, text)</para>
        /// </example>
        /// <param name="fileName">保存先のファイル名</param>
        /// <param name="text">テキストデータ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void saveCsvData(string fileName, string text)
        {
            StreamWriter sw = null;

            try
            {
                // ファイルのオープン(現在のWindowsコードページに設定されているエンコーディング)
                sw = new StreamWriter(fileName, false, Encoding.Default);
                // データの書き込み
                sw.Write(text);
                // メッセージ:ファイルを保存しました。
                MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_INFO_FILE_SAVED,
                    Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE, MessageBoxButtons.OK, MessageBoxIcon.Information);

            }
            catch
            {
                // メッセージ:ファイルが保存できませんでした。
                MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_FAILED_TO_SAVE_FILE,
                    Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                if (sw != null)
                {
                    sw.Close();
                }
            }
        }

        #endregion

        #region CSVのトークンの生成

        /// <summary><para>method outline:</para>
        /// <para>CSVのトークン生成</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>string strCsvToken = csvToken(str, tabDelim)</para>
        /// </example>
        /// <param name="str">加工を行う文字列</param>
        /// <param name="tabDelim">true:末尾にタブ文字を付ける、false:末尾にタブ文字を付けない</param>
        /// <returns>加工を行った文字列</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>基本的に指定された文字列の末尾にカンマを付けるだけだが、指定された文字にカンマかダブルクォートが含まれていたらエスケープして前後をダブルクォートでくくる</para>
        /// </remarks>
        private string csvToken(string str, bool tabDelim)
        {
            if (str == null)
            {
                str = "";
            }

            if (tabDelim)
            {
                str += "\t";
            }
            else if (str.IndexOf(",") >= 0 || str.IndexOf("\"") >= 0)
            {
                if (str.IndexOf("\"") >= 0)
                {
                    // " を "" に変換
                    str = str.Replace("\"", "\"\"");
                }
                // 前後を " でくくる
                str = "\"" + str + "\",";
            }
            else
            {
                // 末尾にカンマをつける
                str += ",";
            }

            return (str);
        }

        #endregion

        #region CSVの行末の処理

        /// <summary><para>method outline:</para>
        /// <para>指定された文字列の末尾がカンマだった場合、改行コードに置換する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>string strCsvTail = csvTail(str)</para>
        /// </example>
        /// <param name="str">加工を行う文字列</param>
        /// <returns>加工を行った文字列</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private string csvTail(string str)
        {
            if (str != null && str.Length > 0)
            {
                if (str.Substring(str.Length - 1).Equals(",")
                 || str.Substring(str.Length - 1).Equals("\t"))
                {
                    str = str.Substring(0, str.Length - 1) + "\r\n";
                }
            }
            return (str);
        }

        #endregion

        #region CSVデータの生成

        /// <summary><para>method outline:</para>
        /// <para>グラフに表示しているデータをCSV形式で返す</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>string strCsvData = getCsvData(tabDelim)</para>
        /// </example>
        /// <param name="tabDelim">true:末尾にタブ文字を付ける、false:末尾にタブ文字を付けない</param>
        /// <returns>CSVデータ</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private string getCsvData(bool tabDelim)
        {
            // 河川名のチェック
            if (cboRiver.Text == null || cboRiver.Text.Length <= 0)
            {
                // メッセージ:河川名を選択してください。
                MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_SELECT_RIVER_NAME,
                    Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE);
                return (null);
            }

            // 河川データ(データ系列)の取得
            string river = cboRiver.Text;
            RiverData rd = Util.GetRiverData(_commonData, river);
            if (rd == null || rd.GraphPropList == null || rd.GraphPropList.Count <= 0)
            {
                // メッセージ:データ系列を設定してください。
                MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_SET_DATA_SERIES,
                    Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE);
                return (null);
            }

            // データ格納用のバッファ
            StringBuilder body = new StringBuilder();
            string line = "";

            List<string[]> data = new List<string[]>();

            // 「河川名」カラムのデータ取得
            data.Add(Util.GetData(_commonData, river, Util.ConvertFileId(_commonData, 0), CommonData.KEY_RIVER_NM));
            line += csvToken(CommonData.KEY_RIVER_NM, tabDelim);
            // 「topoID」カラムのデータ取得
            data.Add(Util.GetData(_commonData, river, Util.ConvertFileId(_commonData, 0), CommonData.KEY_TOPO_ID));
            line += csvToken(CommonData.KEY_TOPO_ID, tabDelim);
            // 「断面No」カラムのデータ取得
            data.Add(Util.GetData(_commonData, river, Util.ConvertFileId(_commonData, 0), CommonData.KEY_SLICE_NO));
            line += csvToken(CommonData.KEY_SLICE_NO, tabDelim);
            // 「累加距離」カラムのデータ取得
            data.Add(Util.GetData(_commonData, river, Util.ConvertFileId(_commonData, 0), CommonData.KEY_SUM_DISTANCE));
            line += csvToken(CommonData.KEY_SUM_DISTANCE, tabDelim);
            // データ系列設定に従って各項目のデータを取得
            for (int idx = 0; idx < rd.GraphPropList.Count; idx++)
            {
                string[] csv = Util.GetData(_commonData, river, rd.GraphPropList[idx].FileId, rd.GraphPropList[idx].ColumnNm);
                if (csv != null)
                {
                    data.Add(csv);
                    line += csvToken(rd.GraphPropList[idx].ColumnNm, tabDelim);
                }
            }
            // 一行目(項目名)を保存
            body.Append(csvTail(line));
            line = "";

            // データ配列のチェック(通常ありえない)
            if (data[0] == null || data[0].Length <= 0)
            {
                return (null);
            }

            // CSVデータを一行ずつ生成
            for (int row = 0; row < data[0].Length; row++)
            {
                for (int col = 0; col < data.Count; col++)
                {
                    if (data[col] != null && row < data[col].Length)
                    {
                        line += csvToken(data[col][row], tabDelim);
                    }
                }
                body.Append(csvTail(line));
                line = "";
            }

            return (body.ToString());
        }

        #endregion

        #region ズーム関連の描画更新

        /// <summary><para>method outline:</para>
        /// <para>ズーム関連の描画更新をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>UpdateZoomState()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void UpdateZoomState()
        {
            if (!_bCapture)
            {
                return;
            }

            if (_rectGraph.X < 0)
            {
                pboxGraph.Cursor = System.Windows.Forms.Cursors.Default;
            }
            else if (_zoomState == ZoomState.ZOOMIN)
            {
                pboxGraph.Cursor = System.Windows.Forms.Cursors.Cross;
            }
            else if (_zoomState == ZoomState.MOVE)
            {
                pboxGraph.Cursor = System.Windows.Forms.Cursors.SizeAll;
            }
            else
            {
                pboxGraph.Cursor = System.Windows.Forms.Cursors.Default;
            }

            msZoomin.Enabled = cmsZoomin.Enabled = (_rectGraph.X < 0 || _zoomState == ZoomState.ZOOMIN) ? false : true;
            msZoomout.Enabled = cmsZoomout.Enabled = _bZoom;
            msMove.Enabled = cmsMove.Enabled = _bZoom;

            if (_listZoomHistory.Count <= 0)
            {
                msZoomPrev.Enabled = cmsZoomPrev.Enabled = false;
                msZoomNext.Enabled = cmsZoomNext.Enabled = false;
            }
            else
            {
                msZoomPrev.Enabled = cmsZoomPrev.Enabled = (_indexZoomHistory > 0) ? true : false;
                msZoomNext.Enabled = cmsZoomNext.Enabled = (_indexZoomHistory + 1 < _listZoomHistory.Count) ? true : false;
            }
        }

        #endregion

        #region 選択矩形の描画

        /// <summary><para>method outline:</para>
        /// <para>選択矩形を点線で描画する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>drawReversibleRectangle(pt1, pt2)</para>
        /// </example>
        /// <param name="pt1">ポイント1</param>
        /// <param name="pt2">ポイント2</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void drawReversibleRectangle(Point pt1, Point pt2)
        {
            if (!_bCapture)
            {
                return;
            }

            if (bHaveMouse && pt1.X != -1 && pt2.X != -1)
            {
                Rectangle rect = new Rectangle();

                pt1 = pboxGraph.PointToScreen(pt1);
                pt2 = pboxGraph.PointToScreen(pt2);

                rect.X = Math.Min(pt1.X, pt2.X);
                rect.Width = Math.Abs(pt1.X - pt2.X);
                rect.Y = Math.Min(pt1.Y, pt2.Y);
                rect.Height = Math.Abs(pt1.Y - pt2.Y);
                ControlPaint.DrawReversibleFrame(rect, Color.Black, FrameStyle.Dashed);
            }
        }

        #endregion

        #region ズーム履歴の消去

        /// <summary><para>method outline:</para>
        /// <para>全てのズーム履歴を消去する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ResetZoomHistory()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ResetZoomHistory()
        {
            _listZoomHistory.Clear();
            _indexZoomHistory = -1;
        }

        #endregion

        #region ズーム履歴の追加

        /// <summary><para>method outline:</para>
        /// <para>ズーム履歴に現在のズームを追加する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>addZoomHistory()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void addZoomHistory()
        {
            if (!_bZoom)
            {
                _rectZoom = new RectangleF(0.0F, 0.0F, 1.0F, 1.0F);
            }
            if (_indexZoomHistory < 0)
            {
                ResetZoomHistory();
                _indexZoomHistory = 0;
            }
            else
            {
                _indexZoomHistory++;
                if (_indexZoomHistory < _listZoomHistory.Count)
                {
                    _listZoomHistory.RemoveRange(_indexZoomHistory, _listZoomHistory.Count - _indexZoomHistory);
                }
            }
            _listZoomHistory.Add(_rectZoom);
        }

        #endregion

        #region ズーム履歴の変更

        /// <summary><para>method outline:</para>
        /// <para>ズームを現在の履歴で更新する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>changeZoomHistory()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void changeZoomHistory()
        {
            _rectZoom = _listZoomHistory[_indexZoomHistory];
            if (_rectZoom.X == 0.0F && _rectZoom.Y == 0.0F
                && _rectZoom.Width == 1.0F && _rectZoom.Height == 1.0F)
            {
                _bZoom = false;
            }
            else
            {
                _bZoom = true;
            }

            UpdateGraph(false);
        }

        #endregion

        #endregion

        #region イベントメソッド

        #region フォームロード時

        /// <summary><para>method outline:</para>
        /// <para>フォームロード時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void GraphMain_Load(object sender, EventArgs e)
        {
            // 凡例ウィンドウの生成
            legendWindow = new GraphNotes(_commonData);

            // 初期画面サイズの設定
            this.Width = 765;
            this.Height = 500;

            if (_bZoomFunction == false)
            {
                // トップメニュー
                msZoomin.Visible = false;
                msZoomout.Visible = false;
                msMove.Visible = false;
                msZoomPrev.Visible = false;
                msZoomNext.Visible = false;
                msZoomSeparator.Visible = false;

                // コンテキストメニュー
                cmsZoomin.Visible = false;
                cmsZoomout.Visible = false;
                cmsMove.Visible = false;
                cmsZoomPrev.Visible = false;
                cmsZoomNext.Visible = false;
                cmsZoomSeparator.Visible = false;
            }

            // グラフ画面更新
            UpdateGraph(true);
        }

        #endregion

        #region フォームクローズ前

        /// <summary><para>method outline:</para>
        /// <para>フォームをクローズする直前の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void GraphMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                legendWindow.Close();
            }
            catch { }
        }

        #endregion

        #region [ファイル]-[閉じる]時

        /// <summary><para>method outline:</para>
        /// <para>[ファイル]-[閉じる]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msClose_Click(object sender, EventArgs e)
        {
            this.Hide();
        }

        #endregion

        #region [ファイル]-[csv形式で保存]時

        /// <summary><para>method outline:</para>
        /// <para>[ファイル]-[csv形式で保存]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msSaveCsv_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = Properties.HySAddinLsor2VieweEXEResources.FILE_DLG_FILTER_CSV_ALL;
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                // csvデータの取得
                string text = getCsvData(false);
                if (text == null || text.Length <= 0)
                {
                    // メッセージ:保存するデータがありません。
                    MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_NO_DATA_TO_SAVE,
                        Properties.HySAddinLsor2VieweEXEResources.CAPTION_DATA_STORAGE);
                }
                else
                {
                    // csvの保存
                    saveCsvData(saveFileDialog1.FileName, text);
                }
            }
            saveFileDialog1.Dispose();
        }

        #endregion

        #region [csv形式でコピー]時

        /// <summary><para>method outline:</para>
        /// <para>コンテキストメニューで[csv形式でコピー]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void cmsCopyCsv_Click(object sender, EventArgs e)
        {
            // クリップボードにコピー
            Clipboard.SetDataObject(getCsvData(true));
        }

        #endregion

        #region [ファイル]-[emf形式で保存]時

        /// <summary><para>method outline:</para>
        /// <para>[ファイル]-[emf形式で保存]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msSaveEmf_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = Properties.HySAddinLsor2VieweEXEResources.FILE_DLG_FILTER_EMF_ALL;
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                // メタファイルオブジェクト
                Metafile mf = null;

                try
                {
                    // メタファイル保存用のメモリ
                    using (MemoryStream ms = new MemoryStream())
                    {
                        // メタファイルとGDIの紐付け
                        using (Graphics g = CreateGraphics())
                        {
                            IntPtr ipHdc = g.GetHdc();
                            mf = new Metafile(ms, ipHdc, EmfType.EmfPlusDual);
                            g.ReleaseHdc(ipHdc);
                        }

                        // グラフの描画
                        using (Graphics g2 = Graphics.FromImage(mf))
                        {
                            drawGraph(g2);
                        }

                        // ファイル保存
                        using (FileStream fsm = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write))
                        {
                            fsm.Write(ms.GetBuffer(), 0, (int)ms.Length);
                            fsm.Close();
                        }
                    }
                    // 正常保存
                    // メッセージ:ファイルを保存しました。"
                    MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_INFO_FILE_SAVED,
                        Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE, MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch
                {
                    // 保存失敗
                    // メッセージ:ファイルが保存できませんでした。
                    MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_FAILED_TO_SAVE_FILE,
                        Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    if (mf != null)
                    {
                        mf.Dispose();
                    }
                }
            }
            saveFileDialog1.Dispose();
        }

        #endregion

        #region [emf形式でコピー]時

        #region クリップボード関連の定義

        private const int CF_ENHMETAFILE = 14;

        /// <summary>クリップボードを開く</summary>
        /// <param name="hWndNewOwner">ウィンドウのハンドル</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern bool OpenClipboard(IntPtr hWndNewOwner);
        /// <summary>クリップボードを閉じる</summary>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern bool CloseClipboard();
        /// <summary>データがクリップボードに格納されているか調べる</summary>
        /// <param name="wFormat">クリップボードのデータ形式</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern int IsClipboardFormatAvailable(int wFormat);
        /// <summary>クリップボードからデータを取得する</summary>
        /// <param name="wFormat">クリップボードのデータ形式</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern IntPtr GetClipboardData(int wFormat);
        /// <summary>拡張メタファイルの内容を指定されたファイルへコピーする</summary>
        /// <param name="hemfSrc">コピー元の拡張メタファイルのハンドル</param>
        /// <param name="hNULL">コピー先のファイル名へのポインタ</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("gdi32.dll")]
        private static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
        /// <summary>クリップボードを空にする</summary>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern bool EmptyClipboard();
        /// <summary>クリップボードに指定されたデータ形式でデータを格納する</summary>
        /// <param name="uFormat">クリップボードのデータ形式</param>
        /// <param name="hMem">指定されたデータ形式のデータのハンドル</param>
        /// <returns>成功:データのハンドル、失敗:NULL</returns>
        [DllImport("user32.dll")]
        private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
        /// <summary>張メタファイルまたは拡張メタファイルのハンドルを削除する</summary>
        /// <param name="hemf">拡張メタファイルのハンドル</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("gdi32.dll")]
        private static extern bool DeleteEnhMetaFile(IntPtr hemf);

        #endregion

        /// <summary><para>method outline:</para>
        /// <para>コンテキストメニューで[emf形式でコピー]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void cmsCopyEmf_Click(object sender, EventArgs e)
        {
            // メタファイルオブジェクト
            Metafile mf = null;

            try
            {
                // メタファイル格納用のメモリ
                using (MemoryStream ms = new MemoryStream())
                {
                    // メタファイルとGDIの紐付け
                    using (Graphics g = CreateGraphics())
                    {
                        IntPtr ipHdc = g.GetHdc();
                        mf = new Metafile(ms, ipHdc, EmfType.EmfPlusDual);
                        g.ReleaseHdc(ipHdc);
                    }

                    // グラフの描画
                    using (Graphics g2 = Graphics.FromImage(mf))
                    {
                        drawGraph(g2);
                    }

                    // クリッポボードにメタファイル形式でコピー
                    IntPtr hEMF, hEMF2;
                    hEMF = mf.GetHenhmetafile();
                    if (!hEMF.Equals(new IntPtr(0)))
                    {
                        hEMF2 = CopyEnhMetaFile(hEMF, new IntPtr(0));
                        if (!hEMF2.Equals(new IntPtr(0)))
                        {
                            if (OpenClipboard(this.Handle))
                            {
                                if (EmptyClipboard())
                                {
                                    IntPtr hRes = SetClipboardData(CF_ENHMETAFILE, hEMF2);
                                    hRes.Equals(hEMF2);
                                }
                                CloseClipboard();
                            }
                        }
                    }
                    DeleteEnhMetaFile(hEMF);
                }
            }
            catch { }
            mf.Dispose();
        }

        #endregion

        #region 表示設定ダイアログの表示

        /// <summary><para>method outline:</para>
        /// <para>メニューやボタンで「表示設定」が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ShowSettingDialog(object sender, EventArgs e)
        {
            // 現在の河川名をチェック
            if (cboRiver.Text == null || cboRiver.Text.Length <= 0)
            {
                // メッセージ:河川名を選択してください。
                MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_SELECT_RIVER_NAME,
                    Properties.HySAddinLsor2VieweEXEResources.CAPTION_DISPLAY_SETTING);
            }
            else
            {
                // 表示設定ダイアログの表示
                GraphSetting f = new GraphSetting(_commonData);
                f.CurrentRiver = cboRiver.Text;
                DialogResult dr = f.ShowDialog(this);
                f.Dispose();

                // グラフの更新
                if (dr == DialogResult.OK)
                {
                    UpdateGraph(false);
                }
            }
        }

        #endregion

        #region データ系列ダイアログの表示

        /// <summary><para>method outline:</para>
        /// <para>メニューやボタンで「データ系列」が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ShowGraphPropDialog(object sender, EventArgs e)
        {
            // 現在の河川名のチェック
            if (cboRiver.Text == null || cboRiver.Text.Length <= 0)
            {
                // メッセージ:河川名を選択してください。
                MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_SELECT_RIVER_NAME,
                    Properties.HySAddinLsor2VieweEXEResources.CAPTION_DATA_SERIES);
            }
            else
            {
                // データ系列ダイアログの表示
                GraphProp f = new GraphProp(_commonData);
                f.CurrentRiver = cboRiver.Text;
                DialogResult dr = f.ShowDialog(this);
                f.Dispose();

                // グラフの更新
                if (dr == DialogResult.OK)
                {
                    UpdateGraph(false);
                }
            }
        }

        #endregion

        #region 凡例ウィンドウの表示

        /// <summary><para>method outline:</para>
        /// <para>凡例ウィンドウの表示処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void ShowLegendWindow(object sender, EventArgs e)
        {
            if (legendWindow == null || legendWindow.IsDisposed)
            {
                // 凡例ウィンドウオブジェクトが無効の場合
                legendWindow = new GraphNotes(_commonData);
                legendWindow.Show();
            }
            else if (legendWindow.Visible == false)
            {
                // 凡例ウィンドウが非表示の場合
                legendWindow.SetCommonData(_commonData);
                legendWindow.Show();
            }
            else
            {
                // 凡例ウィンドウが背面にある場合
                legendWindow.SetCommonData(_commonData);
                legendWindow.Activate();
            }
            // 凡例の再描画
            legendWindow.UpdateLegend(cboRiver.Text);
        }

        #endregion

        #region 河川選択コンボ変更時

        /// <summary><para>method outline:</para>
        /// <para>河川選択用のコンボボックスが変更された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void cboRiver_SelectedIndexChanged(object sender, EventArgs e)
        {
            // ズームのリセット
            _rectGraph.X = _rectGraph.Y = -1;
            _zoomState = ZoomState.NONE;
            _bZoom = false;
            ResetZoomHistory();
            UpdateZoomState();

            // グラフの再描画
            UpdateGraph(false);

            addZoomHistory();
        }

        #endregion

        #region グラフウィンドウのサイズ変更時

        /// <summary><para>method outline:</para>
        /// <para>グラフウィンドウのサイズが変更された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void pboxGraph_SizeChanged(object sender, EventArgs e)
        {
            // 表示一時停止
            pboxGraph.SuspendLayout();

            // グラフの再描画
            if (pboxGraph.Image == null)
            {
                pboxGraph.Image = new Bitmap(2048, 2048);
            }
            Graphics g = Graphics.FromImage(pboxGraph.Image);
            drawGraph(g);
            pboxGraph.Refresh();
            g.Dispose();

            // 表示再開
            pboxGraph.ResumeLayout();
        }

        #endregion

        #region 更新ボタン押下時

        /// <summary><para>method outline:</para>
        /// <para>[更新]ボタンが押された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void cmdUpdate_Click(object sender, EventArgs e)
        {
            // グラフの再描画
            UpdateGraph(false);
        }

        #endregion

        #region [ズームイン]時

        /// <summary><para>method outline:</para>
        /// <para>メニューで[ズームイン]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msZoomin_Click(object sender, EventArgs e)
        {
            if (_rectGraph.X >= 0 && msZoomin.Enabled)
            {
                _zoomState = ZoomState.ZOOMIN;
            }
            else
            {
                _zoomState = ZoomState.NONE;
            }
            UpdateZoomState();
        }

        #endregion

        #region [ズームアウト]時

        /// <summary><para>method outline:</para>
        /// <para>メニューで[ズームアウト]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msZoomout_Click(object sender, EventArgs e)
        {
            _bZoom = false;
            _zoomState = ZoomState.NONE;
            _rectZoom = new RectangleF(0.0F, 0.0F, 1.0F, 1.0F);
            UpdateZoomState();

            UpdateGraph(false);

            addZoomHistory();
        }

        #endregion

        #region [移動]時

        /// <summary><para>method outline:</para>
        /// <para>メニューで[移動]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msMove_Click(object sender, EventArgs e)
        {
            if (_rectGraph.X >= 0 && msMove.Enabled)
            {
                _zoomState = ZoomState.MOVE;
            }
            else
            {
                _zoomState = ZoomState.NONE;
            }
            UpdateZoomState();
        }

        #endregion

        #region マウスボタン押下時の処理

        /// <summary><para>method outline:</para>
        /// <para>マウスのボタンを押下した時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void pboxGraph_MouseDown(object sender, MouseEventArgs e)
        {
            if (!_bCapture)
            {
                return;
            }

            if (e.Button == MouseButtons.Right)
            {
                pboxGraph_MouseUp(sender, e);

                _zoomState = ZoomState.NONE;
                UpdateZoomState();
            }
            else if (e.Button == MouseButtons.Left)
            {
                if (_rectGraph.X >= 0
                 && _rectGraph.X < e.X && e.X <= _rectGraph.Right
                 && _rectGraph.Y < e.Y && e.Y < _rectGraph.Bottom)
                {
                    if (_zoomState == ZoomState.ZOOMIN)
                    {
                        bHaveMouse = true;
                        ptOrigin = new Point(e.X, e.Y);
                        ptCurrent = new Point(-1, -1);
                    }
                    else if (_zoomState == ZoomState.MOVE)
                    {
                        bHaveMouse = true;
                        ptOrigin = new Point(e.X, e.Y);
                        ptCurrent = new Point(-1, -1);
                    }
                }
            }
        }

        #endregion

        #region マウスボタン開放時

        /// <summary><para>method outline:</para>
        /// <para>マウスのボタンを開放した時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void pboxGraph_MouseUp(object sender, MouseEventArgs e)
        {
            if (!_bCapture)
            {
                return;
            }

            if (_zoomState != ZoomState.NONE)
            {
                if (e.Button == MouseButtons.Left)
                {
                    if (_zoomState == ZoomState.MOVE)
                    {
                        if (bHaveMouse)
                        {
                            addZoomHistory();
                        }
                    }
                    if (_zoomState == ZoomState.ZOOMIN)
                    {
                        drawReversibleRectangle(ptOrigin, ptCurrent);

                        if (!_bZoom)
                        {
                            _rectZoom = new RectangleF(0.0F, 0.0F, 1.0F, 1.0F);
                        }
                        _bZoom = true;

                        int nsx = Math.Min(ptOrigin.X, ptCurrent.X);
                        int nex = Math.Max(ptOrigin.X, ptCurrent.X);
                        if (nsx == nex)
                        {
                            nex = nsx + 1;
                        }
                        int nsy = Math.Min(ptOrigin.Y, ptCurrent.Y);
                        int ney = Math.Max(ptOrigin.Y, ptCurrent.Y);
                        if (nsy == ney)
                        {
                            ney = nsy + 1;
                        }

                        int osx = Math.Min(_rectGraph.X, _rectGraph.Right);
                        int oex = Math.Max(_rectGraph.X, _rectGraph.Right);
                        if (osx == oex)
                        {
                            oex = osx + 1;
                        }
                        int osy = Math.Min(_rectGraph.Y, _rectGraph.Bottom);
                        int oey = Math.Max(_rectGraph.Y, _rectGraph.Bottom);
                        if (osy == oey)
                        {
                            oey = osy + 1;
                        }

                        RectangleF rectNew = new RectangleF();
                        rectNew.X = _rectZoom.X + (_rectZoom.Right - _rectZoom.X) * (float)(nsx - osx) / (float)(oex - osx);
                        rectNew.Width = (_rectZoom.Right - _rectZoom.X) * (float)(nex - nsx) / (float)(oex - osx);
                        rectNew.Y = _rectZoom.Y + (_rectZoom.Bottom - _rectZoom.Y) * (float)(oey - ney) / (float)(oey - osy);
                        rectNew.Height = (_rectZoom.Bottom - _rectZoom.Y) * (float)(ney - nsy) / (float)(oey - osy);
                        if (rectNew.Width > 0.001F)
                        {
                            _rectZoom.X = rectNew.X;
                            _rectZoom.Width = rectNew.Width;
                        }
                        else
                        {
                            _rectZoom.Width = 0.01F;
                        }
                        if (rectNew.Height > 0.001F)
                        {
                            _rectZoom.Y = rectNew.Y;
                            _rectZoom.Height = rectNew.Height;
                        }
                        else
                        {
                            _rectZoom.Height = 0.01F;
                        }

                        addZoomHistory();

                        Graphics g = Graphics.FromImage(pboxGraph.Image);
                        drawGraph(g);
                        pboxGraph.Refresh();
                        g.Dispose();
                    }
                }

                bHaveMouse = false;
                ptCurrent = new Point(-1, -1);
                ptOrigin = new Point(-1, -1);

                _zoomState = ZoomState.NONE;
                UpdateZoomState();
            }
        }

        #endregion

        #region マウス移動時

        /// <summary><para>method outline:</para>
        /// <para>マウスを移動したときの処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void pboxGraph_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_bCapture)
            {
                return;
            }

            if (_zoomState == ZoomState.ZOOMIN || _zoomState == ZoomState.MOVE)
            {
                if (_zoomState == ZoomState.ZOOMIN)
                {
                    drawReversibleRectangle(ptOrigin, ptCurrent);
                }

                int x = e.X;
                if (x <= _rectGraph.X)
                {
                    x = _rectGraph.X + 1;
                }
                if (x >= _rectGraph.Right)
                {
                    x = _rectGraph.Right - 1;
                }
                int y = e.Y;
                if (y <= _rectGraph.Y)
                {
                    y = _rectGraph.Y + 1;
                }
                if (y >= _rectGraph.Bottom)
                {
                    y = _rectGraph.Bottom - 1;
                }
                ptCurrent = new Point(x, y);

                if (_zoomState == ZoomState.ZOOMIN)
                {
                    drawReversibleRectangle(ptOrigin, ptCurrent);
                }
                else if (_zoomState == ZoomState.MOVE && bHaveMouse)
                {
                    _rectZoom.X += _rectZoom.Width * (float)(ptOrigin.X - ptCurrent.X) / (float)_rectGraph.Width;
                    if (_rectZoom.X < 0.0F)
                    {
                        _rectZoom.X = 0.0F;
                    }
                    else if (_rectZoom.X + _rectZoom.Width > 1.0F)
                    {
                        _rectZoom.X = 1.0F - _rectZoom.Width;
                    }
                    _rectZoom.Y += _rectZoom.Height * (float)(ptCurrent.Y - ptOrigin.Y) / (float)_rectGraph.Height;
                    if (_rectZoom.Y < 0.0F)
                    {
                        _rectZoom.Y = 0.0F;
                    }
                    else if (_rectZoom.Y + _rectZoom.Height > 1.0F)
                    {
                        _rectZoom.Y = 1.0F - _rectZoom.Height;
                    }

                    Graphics g = Graphics.FromImage(pboxGraph.Image);
                    drawGraph(g);
                    pboxGraph.Refresh();
                    g.Dispose();

                    ptOrigin = ptCurrent;
                }
            }
        }

        #endregion

        #region [表示]メニュー展開時

        /// <summary><para>method outline:</para>
        /// <para>[表示]メニュー展開時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msView_DropDownOpening(object sender, EventArgs e)
        {
            UpdateZoomState();
        }

        #endregion

        #region コンテキストメニュー展開時

        /// <summary><para>method outline:</para>
        /// <para>コンテキストメニュー展開時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            UpdateZoomState();
        }

        #endregion

        #region [前のズーム]時

        /// <summary><para>method outline:</para>
        /// <para>メニューで[前のズーム]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msZoomPrev_Click(object sender, EventArgs e)
        {
            if (msZoomPrev.Enabled
                && _indexZoomHistory > 0
                && _listZoomHistory.Count >= _indexZoomHistory)
            {
                _indexZoomHistory--;
                changeZoomHistory();
            }
        }

        #endregion

        #region [次のズーム]時

        /// <summary><para>method outline:</para>
        /// <para>メニューで[次のズーム]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void msZoomNext_Click(object sender, EventArgs e)
        {
            if (msZoomNext.Enabled
                && _indexZoomHistory + 1 < _listZoomHistory.Count)
            {
                _indexZoomHistory++;
                changeZoomHistory();
            }
        }

        #endregion

        #region [印刷関係]
// start of 印刷機能追加
        /// <summary><para>method outline:</para>
        /// <para>取得領域ビットマップ化処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> Bitmap btmp = CaptureControl( ctrl )</para>
        /// </example>
        /// <param name="ctrl">ウインドウ部品（コントロール）</param>
        /// <returns>Bitmap : 取得領域内の画像</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public Bitmap CaptureControl(Control ctrl)
        {
            Graphics g = ctrl.CreateGraphics();
            //ctrl（panel）の大きさのBitmapを生成
            Bitmap b_img = new Bitmap(ctrl.ClientRectangle.Width, ctrl.ClientRectangle.Height, g);
            Graphics memg = Graphics.FromImage(b_img);
            //BitBltの引数の用意
            IntPtr dc1 = g.GetHdc();
            IntPtr dc2 = memg.GetHdc();
            const int SRCCOPY = 0xCC0020;
            //Bitmap取得
            BitBlt(dc2, 0, 0, b_img.Width, b_img.Height, dc1, 0, 0, SRCCOPY);
            //解放処理
            g.ReleaseHdc(dc1);
            memg.ReleaseHdc(dc2);
            memg.Dispose();
            g.Dispose();
            return b_img;
        }

        /// <summary><para>method outline:</para>
        /// <para>プリントイベント処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> pd_PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage)</para>
        /// </example>
        /// <param name="sender">object</param>
        /// <param name="e">プリントイベント(PrintPageEvent)</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            //画像を描画する
            e.Graphics.DrawImage(m_bit_img, 0, 0);
            //印刷の次のページがないこと
            e.HasMorePages = false;
            //bitmap解放
            //m_bit_img.Dispose();
        }

        /// <summary><para>method outline:</para>
        /// <para>印刷処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> cmdPrint_Click( sender, e )：（印刷ボタンクリック）</para>
        /// </example>
        /// <param name="sender">object</param>
        /// <param name="e">Event</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void cmdPrint_Click(object sender, EventArgs e)
        {
            //印刷用ビットマップの取得
            m_bit_img = (CaptureControl(panel1));

            //プリントドキュメントの生成
            m_pd = new System.Drawing.Printing.PrintDocument();

            //PrintPageイベントハンドラの追加
            m_pd.PrintPage +=
                new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage);

            //プリントダイアログの生成
            PrintDialog pdlg = new PrintDialog();
            pdlg.UseEXDialog = true;
            //PrintDocumentを指定
            pdlg.Document = m_pd;
            //印刷の選択ダイアログを表示する
            if (pdlg.ShowDialog() == DialogResult.OK)
            {
                //OKがクリックされた時は印刷する
                m_pd.Print();
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>印刷プレビュー表示処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para> cmdPrintPreview_Click( sender, e )：（印刷ﾌﾟﾚﾋﾞｭｰボタンクリック）</para>
        /// </example>
        /// <param name="sender">object</param>
        /// <param name="e">Event</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void cmdPrintPreview_Click(object sender, EventArgs e)
        {
            // start of 印刷プレビュー処理修正
            try
            {
                //印刷用ビットマップの取得
                m_bit_img = (CaptureControl(panel1));

                //プリントドキュメントの生成
                m_pd = new System.Drawing.Printing.PrintDocument();

                //PrintPageイベントハンドラの追加
                m_pd.PrintPage +=
                    new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage);

                //プレビューフォームのインスタンス生成
                PrintPreviewDialog ppd = new PrintPreviewDialog();
                //プレビューするPrintDocumentを設定
                ppd.Document = m_pd;
                //印刷プレビューダイアログを表示する
                ppd.ShowDialog();

                m_bit_img.Dispose();
            }
            catch
            {
                // 例外を此処で捕捉して任意処理実施
            }
            // end of 印刷プレビュー処理修正
        }
// end of 印刷機能追加
        #endregion

        #endregion
    }
}
