C# カーブエディタ作成 グラフデータの読み書き

前の記事 bravememo.hatenablog.com

完成図

この動画では点を適当に追加→名前を付けて保存→新規作成でグラフリセット→開くを行っています。


CurveEditor グラフデータの読み書き

データの読み書き

・menuScriptの設定

まずは設定したい項目のクリックイベントを作成します。 (今回は開くと名前を付けて保存) 次にファイルの読み込みと書き込みを行うためにツールバーからsaveFileDialogopenFileDailogをForm上に追加させます。

f:id:Brave345:20191219122819p:plain

次に作成したクリックイベントに~FileDialog1.ShowDialog();を呼べば各項目を選択したとき下記の画像がでるようになります。

f:id:Brave345:20191219122838p:plain

あとはファイルを選択した際に呼ばれるFindOKイベント内で データの読み書きをすれば完成です。 ファイル名は~FileDialog1.FileNameで取得できます。

f:id:Brave345:20191219122909p:plain

・データの保存形式

データはCSVで保存しています。 保存している情報は一行ごとに開始点、制御点、終了点の座標データを保存しています。

保存はSaveでやっており、座標は0~1に変換した状態で保存しています。(今後別のところでグラフデータを読み込みする際データの確認をわかりやすくするため)

クラスを分割

いままでFormクラスに記述してたChageNomalPosXなどの数学系の関数を新しく作成したCMathクラスにまとめました。

ソースコード

Formクラスまで書くと長くなるので追加したクラスだけ掲載します。

class Form1
{
        /// <summary>
        /// 開く
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuPoen_Click(object sender, EventArgs e)
        {
            openFileDialog1.ShowDialog();
        }
        /// <summary>
        /// CSVを開いてグラフを表示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
        {            m_CurvePointControl.LoadGraph(openFileDialog1.FileName);
            pictureBox1.Refresh();//再描画
        }
        /// <summary>
        /// 名前を付けて保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuSaveAdd_Click(object sender, EventArgs e)
        {
            saveFileDialog1.FileName = "new.csv";
            saveFileDialog1.ShowDialog();
        }
        /// <summary>
        /// ファイルをCSVに保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {
            m_CurvePointControl.SaveGraph(saveFileDialog1.FileName);
        }
}
  class CurvePointControl
{
   //データ読み書き機能
        CurveEditorStream m_stream = new CurveEditorStream();

        /// <summary>
        /// CSVデータからグラフの点データを読み込む
        /// </summary>
        /// <returns></returns>
        public void LoadGraph(string s)
        {
            CurveEditorInit();
            m_list = m_stream.Load(s);
        }

        /// <summary>
        /// CSVデータにグラフの点データを書き込む
        /// </summary>
        /// <returns></returns>
        public void SaveGraph(string s)
        {
            m_stream.Save(ref m_list,s);
        }
}
  //CSVからグラフを読み書きするクラス
    class CurveEditorStream
    {
        /// <summary>
        /// 文字列から座標に変換
        /// </summary>
        /// <param name="values"></param>
        CurvePointControl.BezierPoint ToBezierPoint(string[] values)
        {
            //文字列を数値に変換
            CurvePointControl.BezierPoint bp = new CurvePointControl.BezierPoint();
            bp.startPoint.X = CMath.ChageNomalPosX(decimal.Parse(values[0]));
            bp.startPoint.Y = CMath.ChageNomalPosY(decimal.Parse(values[1]));
            bp.controlPoint1.X = CMath.ChageNomalPosX(decimal.Parse(values[2]));
            bp.controlPoint1.Y = CMath.ChageNomalPosY(decimal.Parse(values[3]));
            bp.controlPoint2.X = CMath.ChageNomalPosX(decimal.Parse(values[4]));
            bp.controlPoint2.Y = CMath.ChageNomalPosY(decimal.Parse(values[5]));
            bp.endPoint.X = CMath.ChageNomalPosX(decimal.Parse(values[6]));
            bp.endPoint.Y = CMath.ChageNomalPosY(decimal.Parse(values[7]));
            return bp;
        }
        /// <summary>
        /// CSVからデータを読み込み
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public List<CurvePointControl.BezierPoint> Load(string s)
        {
            List<CurvePointControl.BezierPoint> list = new List<CurvePointControl.BezierPoint>();
            StreamReader file = new StreamReader(s);

              //末尾まで繰り返す
            while (!file.EndOfStream)
            {
               // CSVファイルの一行を読み込む
                string line = file.ReadLine();
                // 読み込んだ一行をカンマ毎に分けて配列に格納する
                string[] values = line.Split(',');
                CurvePointControl.BezierPoint b = ToBezierPoint(values);
                list.Add(b);
            }
            file.Close();
            return list;
        }
        /// <summary>
        /// CSVにデータを書き込む
        /// </summary>
        /// <param name="List"></param>
        public void Save(ref List<CurvePointControl.BezierPoint> List,string s)
        {
            try
            {
                StreamWriter file = new StreamWriter(s, false, Encoding.UTF8);
                int size = List.Count;
                for(int i = 0; i < size;i++)
                {
                    //座標を0~1の間に変換し文字列化させる
                    string [] name = new string[4];
                    name = ToSting(List[i]);
                    file.Write(name[0]+ "," + name[1] + "," + name[2] + "," + name[3] + "\n");
                }
                file.Close();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                Console.WriteLine(e.Message);       // エラーメッセージを表示
            }
        }
        /// <summary>
        ///  //座標を0~1の間に変換し文字列化させる
        /// </summary>
        /// <param name="bs"></param>
        /// <returns></returns>
        public string[] ToSting( CurvePointControl.BezierPoint bs)
        {
            //座標を0~1の間に変換し文字列化させる
            string[] name = new string[4];
            name[0] = CMath.ChageDecimalPosX(bs.startPoint.X).ToString()
                + "," + CMath.ChageDecimalPosY(bs.startPoint.Y).ToString();
            name[1] = CMath.ChageDecimalPosX(bs.controlPoint1.X).ToString()
                + "," + CMath.ChageDecimalPosY(bs.controlPoint1.Y).ToString();
            name[2] = CMath.ChageDecimalPosX(bs.controlPoint2.X).ToString()
                + "," + CMath.ChageDecimalPosY(bs.controlPoint2.Y).ToString();
            name[3] = CMath.ChageDecimalPosX(bs.endPoint.X).ToString()
                + "," + CMath.ChageDecimalPosY(bs.endPoint.Y).ToString();

            return name;
        }
    }
 //カーブエディタで使う数学関数
    class CMath
    {
        /// <summary>
        /// 小数から元の座標に変換
        /// </summary>
        /// <param name="Value"></param>
        /// <returns></returns>
        public static int ChageNomalPosX(decimal Value)
        {
            decimal num = Value;

            decimal num2 = (num * (decimal)500);
            int num3 = Convert.ToInt32(num2);

            num3 += 10;//10からグラフが始まってるので右に+10
            return num3;
        }
        /// <summary>
        /// 元の座標から0~1の間に変換
        /// </summary>
        /// <param name="posX"></param>
        /// <returns></returns>
        public static decimal ChageDecimalPosX(int posX)
        {
            posX = Math.Max(0, posX - 10); //10からグラフが始まってるので右に-10
            return (decimal)posX / (decimal)500;
        }
        
        /// <summary>
        /// 小数から元の座標に変換
        /// </summary>
        /// <param name="Value"></param>
        /// <returns></returns>
        public static int ChageNomalPosY(decimal Value)
        {
            decimal num = Value;

            decimal num2 = num * (decimal)500;
            int num3 = Convert.ToInt32(num2);

            num3 = num3 - 500;
            num3 = num3 * -1;
            num3 += 10;//10からグラフが始まってるので右に+10

            return num3;
        }
        /// <summary>
        /// 元の座標から0~1の間に変換
        /// </summary>
        /// <param name="posY"></param>
        /// <returns></returns>
        public static decimal ChageDecimalPosY(int posY)
        {
            //  posY = Math.Min(500, posY - 10);
            //10からグラフが始まってるので右に-10
            posY = Math.Max(0, posY - 10);
            posY = posY - 500;
            posY = posY * -1;

            return Math.Max(0, (decimal)posY / (decimal)500);
        }
        /// <summary>
        /// 値を制限させる
        /// </summary>
        /// <param name="x"></param>
        /// <param name="minVal"></param>
        /// <param name="maxVal"></param>
        /// <returns></returns>
        public static int Clamp(int x, int minVal, int maxVal)
        {
            return Math.Min(Math.Max(minVal, x), maxVal);
        }
    }

終わりに

カーブエディタ作成もだんだん終わりが近づいてきました。 次は上書き保存を実装していきます。

次の記事

bravememo.hatenablog.com