C# カーブエディタ作成 入力項目の実装その2

前の記事

bravememo.hatenablog.com

完成図

だいぶそれっぽくなってきた。


CurveEditor ver 0 6 α版 入力項目の同期 その2

グラフ、入力項目の表記変更

・大幅に見た目をかえました。 見た目はUniyのAnimationCurveを参考にしました。 pictureobxのサイズを640×340から540×530にし、中で500×500のグラフを表示するようにしました

横長のグラフだとこのグラフを読み込んだ際に縦に伸びてしまい、思ったような挙動にならないはずなので、正方形にしました。

・グラフの表記は画面の座標から1.0,1.0にし、値の調整をわかりやすくしました。

ChageDecimalPos~とChageNomalPos~で座標を変換しています。 方法としてはシンプルで位置をグラフの大きさである500で割ってあげれば0.002まで表現することができます。m_CurvePointControlに座標を渡す際は numericUpDown.Valueの値(0~1)に500をかければ元の座標が出せるのでそれを渡せば今まで通り曲線を表示できます。

グラフの外側にある数値表示

数値表記はlabelでやっていてBackColorをTransparentにしてLavelInitでやっているように pictureBox1.Controls.Addをlabelに対してしてあげれば背景を透過させた文字が表示できます。

labelの配置位置です。白いやつがlabelです。

f:id:Brave345:20191212145900p:plain

pictureBox1.Controls.Addすると位置がデザイン画面で表示している位置とずれます。 おそらく原因としては実行前の配置はFormの相対座標が保存されているがpictureBox1を親にしても、Formの相対座標をそのまま使われてるからだと思われます。 なので配置位置は実行結果見ながら地道に位置をずらしました。 なんかいいやり方はないのかな・・・

処理負荷軽減

いままでRefresh()で描画の更新をしていましたが、それだとForm全体が描画の再更新がかかるため重かったため、Refresh()を pictureBox1.Refresh()にすることで、pictureBoxだけ描画だけ更新することができ、無駄な描画更新が減りました。

点の描画OnOff機能

checkBoxを使用してチェックがついてないときは点の描画処理を呼ばないことで点の描画のOnOffを実装しています。 注意点としてCheckedChangedイベントでRefresh()を呼ばないとチェックの変更を行った際に描画の更新がされないのでCheckedChangedイベントを設定しましょう。

線の色変更、線の追加

0.2ごとに線を追加してグラフっぽくしました。線の表示方法今までのやり方と同じでGraphicsのDrawLineで描画しています。

曲線はにして見やすくしました。UniyのAnimationcurveぽいでしょ?

ソースコード

全部書くと長くなるので大きく変更した部分だけ掲載します。

//Form.cs
 public partial class Form1 : Form
    {
        /// <summary>
        /// 直線
        /// </summary>
        CenterLine m_CenterLine = new CenterLine();
        TopLine m_TopLine = new TopLine();
        BottomLine m_BottomLine = new BottomLine();
        VerticalEndLine m_VerticalLeftLine = new VerticalEndLine(true);
        VerticalEndLine m_VerticalRightLine = new VerticalEndLine(false);

        const int LineNum = 9;
        VerticalLine[] m_VerticalCenterLines = new VerticalLine[LineNum];
        SideLine[] m_SideLine = new SideLine[LineNum];
        /// <summary>
        /// 曲線
        /// </summary>
        CurvePointControl m_CurvePointControl = new CurvePointControl();

        const int ScrrenCenterpPosY = 162;  //中央
        const int ScrrenTopPosY = 10;      //上端
        const int ScrrenBottomPosY = 510;   //下端
        Point m_MousePos;//一時保存用マウスの座標
        CurvePointControl.BezierPoint bp;//一時保存用

        //中心の線を引くためのポイント初期化
        public void StandartPointInit()
        {
            m_CenterLine.Init();
            m_TopLine.Init();
            m_BottomLine.Init();
            m_VerticalLeftLine.Init();
            m_VerticalRightLine.Init();
            for(int i = 0; i < LineNum; i++)
            {
                //縦線
                m_VerticalCenterLines[i] = new VerticalLine((i + 1) * 50  + 10);
                m_VerticalCenterLines[i].Init();
                //横線
                m_SideLine[i] = new SideLine((i + 1) * 50  + 10);
                m_SideLine[i].Init();
            }
         
        }
        //入力項目の初期化
        public void numericUpDownInit()
        {
            //値が変わった時の呼び出されるメソッド設定
            numericUpDown1.ValueChanged += new EventHandler(ChangeSelectPointX);
            numericUpDown2.ValueChanged += new EventHandler(ChangeControlPoint1X);
            numericUpDown3.ValueChanged += new EventHandler(ChangeControlPoint2X);
            numericUpDown4.ValueChanged += new EventHandler(ChangeSelectPointY);
            numericUpDown5.ValueChanged += new EventHandler(ChangeControlPoint1Y);
            numericUpDown6.ValueChanged += new EventHandler(ChangeControlPoint2Y);
            numericUpDown7.ValueChanged += new EventHandler(ChangeEndPoint);
            numericUpDown7.Value = 1;
            numericUpDown8.ValueChanged += new EventHandler(ChangeFirstStartPoint);
            numericUpDown8.Value = 0;
            ChangeFirstStartPoint(null,null);
            ChangeEndPoint(null, null);
        }

        /// <summary>
        /// 背景を透過させるための初期化
        /// </summary>
        public void LavelInit()
        {
            pictureBox1.Controls.Add(label10);
            pictureBox1.Controls.Add(label11);
            pictureBox1.Controls.Add(label12);
            pictureBox1.Controls.Add(label13);
            pictureBox1.Controls.Add(label14);
            pictureBox1.Controls.Add(label15);
            pictureBox1.Controls.Add(label16);
            pictureBox1.Controls.Add(label17);
            pictureBox1.Controls.Add(label18);
            pictureBox1.Controls.Add(label19);
            pictureBox1.Controls.Add(label20);
            pictureBox1.Controls.Add(label21);
        }
        /// <summary>
        /// 点を動かした際同期を取る
        /// </summary>
        public void numericUpDownSync()
        {
            bp = m_CurvePointControl.GetBezierPoint();
            numericUpDown1.Value = ChageDecimalPosX(bp.startPoint.X);
            numericUpDown2.Value = ChageDecimalPosX(bp.controlPoint1.X);
            numericUpDown3.Value = ChageDecimalPosX(bp.controlPoint2.X);
            numericUpDown4.Value = ChageDecimalPosY(bp.startPoint.Y);
            numericUpDown5.Value = ChageDecimalPosY(bp.controlPoint1.Y);
            numericUpDown6.Value = ChageDecimalPosY(bp.controlPoint2.Y);
            numericUpDown7.Value = ChageDecimalPosY(m_CurvePointControl.GetEndPointY());
            numericUpDown8.Value = ChageDecimalPosY(m_CurvePointControl.GetFirstStartPointY());
        }

        /// <summary>
        /// マウスを動かしてる間の処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            m_CurvePointControl.MovePoint(e);
            numericUpDownSync();
          //  Invalidate();重くなるのでいらない
            pictureBox1.Refresh();//再描画
        }  

        /// <summary>
        /// 選択点X
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeSelectPointX(object sender, EventArgs e)
        {
            int num3 = ChageNomalPosX(numericUpDown1.Value);
            int num4 = m_CurvePointControl.SetStartPointX(num3);
            numericUpDown1.Value = ChageDecimalPosX(num4); 
             if (!m_CurvePointControl.isMoveSelectPoint()) pictureBox1.Refresh();//再描画
        }
        /// <summary>
        /// 選択点Y
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeSelectPointY(object sender, EventArgs e)
        {
            int num = ChageNomalPosY(numericUpDown4.Value);
            int num2 = m_CurvePointControl.SetStartPointY(num);
            numericUpDown4.Value = ChageDecimalPosY(num2);
            if (!m_CurvePointControl.isMoveSelectPoint()) pictureBox1.Refresh();//再描画
            //最初の開始点と同期を取る
            numericUpDown8.Value = ChageDecimalPosY(m_CurvePointControl.GetFirstStartPointY());
        }
        /// <summary>
        /// 制御点1X
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeControlPoint1X(object sender, EventArgs e)
        {
            int num = ChageNomalPosX(numericUpDown2.Value);
            int num2 = m_CurvePointControl.SetControl1PointX(num);
            numericUpDown2.Value =ChageDecimalPosX(num2);
             if (!m_CurvePointControl.isMoveSelectPoint())  pictureBox1.Refresh();//再描画
        }
        /// <summary>
        /// 制御点1Y
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeControlPoint1Y(object sender, EventArgs e)
        {
            int num = ChageNomalPosY(numericUpDown5.Value);
            int num2 = m_CurvePointControl.SetControl1PointY(num);
            numericUpDown5.Value = ChageDecimalPosY(num2);
            if (!m_CurvePointControl.isMoveSelectPoint())  pictureBox1.Refresh();//再描画
        }
        /// <summary>
        /// 制御点2X
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeControlPoint2X(object sender, EventArgs e)
        {
            int num = ChageNomalPosX(numericUpDown3.Value);
            int num2 = m_CurvePointControl.SetControl2PointX(num);
            numericUpDown3.Value = ChageDecimalPosX(num2);
            if (!m_CurvePointControl.isMoveSelectPoint())  pictureBox1.Refresh();//再描画
        }
        /// <summary>
        /// 制御点2Y
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeControlPoint2Y(object sender, EventArgs e)
        {
            int num = ChageNomalPosY(numericUpDown6.Value);
            int num2 = m_CurvePointControl.SetControl2PointY(num);
            numericUpDown6.Value = ChageDecimalPosY(num2);
            if (!m_CurvePointControl.isMoveSelectPoint()) pictureBox1.Refresh();//再描画
        }
        //開始点せってい
        public void ChangeFirstStartPoint(object sender, EventArgs e)
        {
            int num = ChageNomalPosY(numericUpDown8.Value);
            int num2 = m_CurvePointControl.SetFirstStartPoint(num); ;
            numericUpDown8.Value = ChageDecimalPosY(num2);
            if (!m_CurvePointControl.isMoveSelectPoint()) pictureBox1.Refresh();//再描画
            bp = m_CurvePointControl.GetBezierPoint();
            numericUpDown4.Value = ChageDecimalPosY( bp.startPoint.Y);
        }
        /// <summary>
        /// 終了点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ChangeEndPoint(object sender, EventArgs e)
        {

            int num = ChageNomalPosY(numericUpDown7.Value);
            int num2 = m_CurvePointControl.SetEndPoint(num); ;
            numericUpDown7.Value = ChageDecimalPosY(num2);
            if (!m_CurvePointControl.isMoveSelectPoint()) pictureBox1.Refresh();//再描画
            bp = m_CurvePointControl.GetBezierPoint();
        }

  
        //小数から元の座標に変換
        public int ChageNomalPosX(decimal Value)
        {
            decimal num = Value;

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

            num3 += 10;//10からグラフが始まってるので右に+10
            return num3;
        }
        //元の座標から0~1の間に変換
        public decimal ChageDecimalPosX(int posX)
        {
            posX = Math.Max(0, posX - 10); //10からグラフが始まってるので右に-10
            return (decimal)posX / (decimal)500;
        }
        //小数から元の座標に変換
        public 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;
        }
        //元の座標から0~1の間に変換
        public 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);
        }
    
        //チェックボックスの値が変化したときに呼ばれる
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            pictureBox1.Refresh();//再描画
        }

終わりに

だいぶカーブエディタも完成に近づいてきました。 この調子で頑張ろう。

次の記事

bravememo.hatenablog.com