目录
三、关键帧编辑
1、新建Winform工程
(1)界面布局
(2)全局变量
2、关键帧添加和删除
(1)鼠标在曲线上识别
(2)键盘按键按下捕捉
(3)关键帧添加、删除
(4)修改关键帧值
3、曲线插值
(1)三次样条插值
(2)工程代码下载链接
四、曲线数据导出和读取
1、数据导出
(1)添加导出按钮
(2)工程代码下载链接
2、读取导出的数据
(1)手动按钮创建曲线
(2)读取导出得关键帧数据
(3)工程代码下载链接
五、全部工程下载
1、基本功能
2、核心功能
接上一节《C#时间轴曲线图形编辑器开发1-基本功能》继续。
C#时间轴曲线图形编辑器开发1-基本功能_Big_潘大师的博客-CSDN博客
三、关键帧编辑
1、新建Winform工程
重新创建新的Winform工程测试
(1)界面布局
(2)全局变量
KeyDatasClass _keyData = new KeyDatasClass();SplineEdit cureDraw;float tensionSpline1 = 0.5f; //曲线1粗细//曲线编辑Dictionary<int, float> keyListDatas = new Dictionary<int, float>(); //关键帧集合Color editSplineColor = Color.Blue; //曲线颜色bool isMouseOnKeyPoint = false; //鼠标是否在关键点上检测int dataLength = 0;float[] myEditDatas; //绘制的曲线数据 int[] KeyDatasflag; //当前曲线数据是否是关键帧数据标值位float[] keyEditDatas_X; //关键帧-方框点绘制-X轴数据float[] keyEditDatas_Y; //关键帧-方框点绘制-X轴数据bool isDataEdit = false; //关键帧是否要编辑bool isKeyEditDataMoveCan = false;int keyEditFrame = 0; //当前要编辑的关键帧数据//鼠标当前在画图面板上的像素坐标,对应的坐标轴数值bool isMouseOnSpline; //鼠标在曲线上检测int currentValue_X;float currentValue_Y;int last_CurrentValueX = 0;int ex = 0, ey = 0; //鼠标的坐标值bool isLeftButtonDowm = false, isMiddleButtonDown = false, isRightButtonDown = false;bool isCtrlKeyDown = false;bool isShiftDown = false;
2、关键帧添加和删除
当检测鼠标在曲线上的时候,通过键盘和鼠标的组合按键操作,可以进行关键帧添加和删除操作。
(1)鼠标在曲线上识别
重新整理曲线识别代码,将其代码封装。将封装好的代码放在timer1_Tick中执行
/// <summary>/// 检测鼠标是否在绘制得曲线上/// </summary>private void MouseOnSplineCheck(){//if (currentValue_X < dataLength){int nIndex = currentValue_X;if (nIndex >= myEditDatas.Length){nIndex = myEditDatas.Length - 1;if (nIndex < 0){nIndex = 0;}}float selectValue_Y = myEditDatas[nIndex];if (Math.Abs(selectValue_Y - currentValue_Y) < cureDraw.YSliceValue / 8){isMouseOnSpline = true;labMousePos.ForeColor = editSplineColor;}else{isMouseOnSpline = false;labMousePos.ForeColor = Color.Black;}}else{labMousePos.ForeColor = Color.Black;}}
(2)键盘按键按下捕捉
①在窗口属性中找到KeyPreview设置为True
②在窗口事件程序中分别添加KeyDowm、KeyUp事件函数
MainForm_KeyDown():
private void MainForm_KeyDown(object sender, KeyEventArgs e){Keys k = e.KeyCode;if (k == Keys.ControlKey){isCtrlKeyDown = true;}if (k == Keys.ShiftKey){isShiftDown = true;}}
MainForm_KeyUp():
private void MainForm_KeyUp(object sender, KeyEventArgs e){Keys k = e.KeyCode;if (k == Keys.ControlKey){isCtrlKeyDown = false;}if (k == Keys.ShiftKey){isShiftDown = false;}}
(3)关键帧添加、删除
①关键帧添加
鼠标在曲线上的时候,Ctrl键+鼠标左键按下,添加关键帧
②关键帧删除
鼠标在曲线上的时候,Shift键+鼠标左键按下,删除当前关键帧
③添加pictureBox1控件的单击事件函数:pictureBox1_Click
private void pictureBox1_Click(object sender, EventArgs e){//添加关键帧数据if(isMouseOnSpline && isCtrlKeyDown){if (currentValue_X > dataLength){MessageBox.Show("数据超过极限范围");return;}//判断关键帧是否可以添加,判断当前要添加的关键帧是否已经存在bool isKeyListCanAdd = false;for (int i = 0; i < keyEditDatas_X.Length; i++){if(currentValue_X!=keyEditDatas_X[i]){isKeyListCanAdd = true;}}for (int i = 0; i < keyEditDatas_X.Length; i++){if (currentValue_X == keyEditDatas_X[i]){isKeyListCanAdd = false;}}if (isKeyListCanAdd){//keyListDatas.Add(currentValue_X, currentValue_Y); //关键帧值设置为当前位置值keyListDatas.Add(currentValue_X, 0.0f); //关键帧值设置为0} }//删除当前关键帧if (isKeyEditDataMoveCan && isShiftDown){keyListDatas.Remove(keyEditFrame); //删除关键帧数据myEditDatas[keyEditFrame] = 0.0f; //将曲线数据值修改为0}}
(4)修改关键帧值
修改关键帧值,除了鼠标拖动外,还要需要可以手动输入操作,这样可以精确的给定关键帧值。
实现方法,鼠标在关键帧的时候右键双击,弹出输入对话框。
①新建窗口
打开该窗口读取当前关键帧值、点击确定或者按回车将输入的值传到关键帧上。
窗口需要设置键盘识别
添加键盘事件:KeyDataSetForm_KeyDown
判断Enter键按下
private void KeyDataSetForm_KeyDown(object sender, KeyEventArgs e){Keys k = e.KeyCode;if (k == Keys.Enter){_Son.KeyDataSet = float.Parse(txtKeyDataSet.Text);this.Close();}if (k == Keys.Escape){this.Close();}}
使用构造函数的方法进行窗口传值。(操作方法见工程代码)
②pictureBox1控件添加双击事件:pictureBox1_DoubleClick
private void pictureBox1_DoubleClick(object sender, EventArgs e){if (isRightButtonDown && (label7.BackColor == Color.Lime)){//MessageBox.Show("123");KeyDataSetForm kdf = new KeyDataSetForm(this, _keyData);_keyData.KeyDataSet = currentValue_Y;kdf.ShowDialog();keyListDatas[keyEditFrame] = _keyData.KeyDataSet;}}
3、曲线插值
插值的目的是,根据当前关键帧的值得到一条完整的连续、圆滑曲线。这时就需要用到插值法,来计算曲线数组每个元素的值。
(1)三次样条插值
插值代码见程序工程。方法是,首先要将关键帧数据进行排序,然后再插值计算。
修改KeyDataTrans()代码,添加三次样条插值
/// <summary>/// 关键帧数据集合转数组/// </summary>private void KeyDataTrans(){//关键点得数据值,对应到曲线数据上foreach (KeyValuePair<int, float> item in keyListDatas){int key = item.Key;float fValue = item.Value;//myEditDatas[key] = fValue;KeyDatasflag[key] = 1; //关键帧所在的地方设置为1}//List<float> fListTemp_X = new List<float> { };List<float> fListTemp_Y = new List<float> { };foreach (KeyValuePair<int, float> item in keyListDatas){int key = item.Key;float fValue = item.Value;fListTemp_X.Add(key);fListTemp_Y.Add(fValue);}keyEditDatas_X = fListTemp_X.ToArray();keyEditDatas_Y = fListTemp_Y.ToArray();//三次样条插值PointClass[] points = new PointClass[keyEditDatas_X.Length];for (int i = 0; i < keyEditDatas_X.Length; i++){points[i] = new PointClass();points[i].x = keyEditDatas_X[i];points[i].y = keyEditDatas_Y[i];}PointClass.DeSortX(points); //排序try{double[] xs = new double[myEditDatas.Length];for (int i = 0; i < myEditDatas.Length; i++){xs[i] = i;}double[] Y = DataInterpolation.SplineInsertPoint(points, xs, 1);if (Y.Length == myEditDatas.Length){for (int i = 0; i < myEditDatas.Length; i++){myEditDatas[i] = (float)Y[i];}}}catch { }}
未使用插值的曲线
使用三次样条插值后曲线
使用三次样条插值后操作演示
(2)工程代码下载链接
代码仅个人使用
链接:https://pan.baidu.com/s/1WLov3JLowmw_YS_wQT7QNw
提取码:fi2f
--来自百度网盘超级会员V4的分享
四、曲线数据导出和读取
1、数据导出
导出数据要求:数据分三列,第一列是行号、第二列是曲线数据、第三列是关键帧标志位。
(1)添加导出按钮
btnSplineDataExport_Click():
private void btnSplineDataExport_Click(object sender, EventArgs e){if (myEditDatas.Length < 1){MessageBox.Show("请先添加数据", "提示");return;}//string[] newLines = new string[myEditDatas.Length];for (int i = 0; i < myEditDatas.Length; i++){if (KeyDatasflag[i] == 1){newLines[i] = "L" + i.ToString() + "\t" + myEditDatas[i].ToString("0.00") + "\t" + "1";}else{newLines[i] = "L" + i.ToString() + "\t" + myEditDatas[i].ToString("0.00") + "\t" + "0";}//newLines[i] = myEditDatas[i].ToString("0.00");}string path = @"C:\Users\Administrator\Desktop\TestData.txt";using (System.IO.StreamWriter file = new System.IO.StreamWriter(path, true)){foreach (string line in newLines){file.WriteLine(line);// 直接追加文件末尾,换行 //file.Write(line);//直接追加文件末尾,不换行}}MessageBox.Show("导出完成", "提示");}
曲线编辑和数据导出
(2)工程代码下载链接
代码仅个人使用
链接:https://pan.baidu.com/s/1Gpbe-fJGOqLdj7VxFTDdcg
提取码:vyyq
--来自百度网盘超级会员V4的分享
2、读取导出的数据
(1)手动按钮创建曲线
将窗口登陆时添加的关键帧数据,改成手动点击按钮生成。
btnDataCreate_Click()
private void btnDataCreate_Click(object sender, EventArgs e){//曲线编辑器数据dataLength = int.Parse(txtDataLength.Text);myEditDatas = new float[dataLength];KeyDatasflag = new int[myEditDatas.Length];//字典集合中添加4个随机数据keyListDatas.Add(100 + dataLength / 2, 40.0f);keyListDatas.Add(0, 0.0f);keyListDatas.Add(dataLength / 2, 10.0f);keyListDatas.Add(dataLength - 1, 0.0f);keyListDatas[dataLength / 2] = 50.0f; //修改字典集合中的值KeyDataTrans();}
修改MainForm_Load()
private void MainForm_Load(object sender, EventArgs e){//timer1.Start();timer2.Start();cureDraw = new SplineEdit(pictureBox1.Height, pictureBox1.Width);DrawCure();}
修改DrawCure()
private void DrawCure(){if (pictureBox1.Height > 0 && pictureBox1.Width > 0) //若窗口最小化时候,则Height、Width都为0。DrawImage()创建图像会出错{cureDraw.Height = pictureBox1.Height;cureDraw.Width = pictureBox1.Width;}pictureBox1.Image = cureDraw.DrawImage();//当前帧指示线cureDraw.DrawCurrentLine(last_CurrentValueX);if (isLeftButtonDowm){last_CurrentValueX = currentValue_X;if (myEditDatas != null){if (last_CurrentValueX > myEditDatas.Length){last_CurrentValueX = myEditDatas.Length;}}}//曲线编辑器if (keyListDatas.Count > 0)//if (keyEditDatas_Y.Length > 0) //绘制关键帧{cureDraw.DrawPoint(keyEditDatas_X, keyEditDatas_Y, editSplineColor, tensionSpline1, true);}if (dataLength > 0)//if (myEditDatas.Length > 0) //绘制曲线{cureDraw.DrawSpline(myEditDatas, editSplineColor, 0.5f, false);}}
(2)读取导出得关键帧数据
btnSplineDataRead():
private void btnSplineDataRead_Click(object sender, EventArgs e){try{OpenFileDialog ofd = new OpenFileDialog();ofd.Filter = "All files(*.*)|*.*|文本文件(*.csv)|*.csv|文本文件(*.txt)|*.txt";if (ofd.ShowDialog() != DialogResult.OK){return;}int dataColumNums = 0; //动作文件列表数int dataLineNums; //double[,] axisDataArrayRead;float[] axis1Datas;string[] lines = File.ReadAllLines(ofd.FileName, Encoding.Default).ToArray();dataColumNums = CharNum(lines[0], "\t");dataLineNums = lines.Length;axisDataArrayRead = new double[dataColumNums, dataLineNums];axis1Datas = new float[dataLineNums];//解析数据for (int i = 0; i < lines.Length; i++){string[] seg = lines[i].Split('\t'); //英文逗号分隔符for (int j = 1; j < dataColumNums; j++) // {axisDataArrayRead[j, i] = Convert.ToDouble(seg[j]);}}//轴1数据for (int i = 0; i < lines.Length; i++){axis1Datas[i] = (float)axisDataArrayRead[1, i];}MessageBox.Show("读取完毕,总共 " + dataLineNums.ToString() + " 行", "提示");//dataLength = dataLineNums;myEditDatas = new float[dataLength];KeyDatasflag = new int[myEditDatas.Length];for (int i = 0; i < dataLength; i++){myEditDatas[i] = (float)axisDataArrayRead[1, i];KeyDatasflag[i] = (int)axisDataArrayRead[2, i];if (KeyDatasflag[i] == 1){keyListDatas.Add(i, myEditDatas[i]);}}}catch{MessageBox.Show("文件解析异常", "提示");}}
(3)工程代码下载链接
3
链接:https://pan.baidu.com/s/1uj4xVkTCpGVTarcqiJCxGA
提取码:w1o9
--来自百度网盘超级会员V4的分享
4
链接:https://pan.baidu.com/s/1Ly3mKv2WZ9mfNCvjKAIDPA
提取码:zydp
--来自百度网盘超级会员V4的分享
五、全部工程下载
1、基本功能
https://download.csdn.net/download/panjinliang066333/88112693
2、核心功能
https://download.csdn.net/download/panjinliang066333/88117382