C#时间轴曲线图形编辑器开发2-核心功能实现
目录
三、关键帧编辑
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
相关文章:

C#时间轴曲线图形编辑器开发2-核心功能实现
目录 三、关键帧编辑 1、新建Winform工程 (1)界面布局 (2)全局变量 2、关键帧添加和删除 (1)鼠标在曲线上识别 (2)键盘按键按下捕捉 (3)关键帧添加、删…...

【Git】初始化仓库配置与本地仓库提交流程
目录 一、仓库配置邮箱与用户名 二、本地仓库提交流程 一、仓库配置邮箱与用户名 【Git】Linux服务器Centos环境下安装Git与创建本地仓库_centos git仓库搭建_1373i的博客-CSDN博客https://blog.csdn.net/qq_61903414/article/details/131260033?spm1001.2014.3001.5501 在…...

学习day53
今天主要是做一个案例 TodoList 组件化编码流程: 1. 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突 2.实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:…...
【最短路算法】SPFA
引入 在计算机科学的世界里,算法就像是星空中的繁星,各自闪烁着智慧的光芒。它们沉默而坚定,像是一群不语的哲人,默默地解答着世界的问题。 算法的步骤,如同优美的诗行,让复杂的问题在流转的字符中得以释…...

牛客网Verilog刷题——VL48
牛客网Verilog刷题——VL48 题目答案 题目 在data_en为高期间,data_in将保持不变,data_en为高至少保持3个B时钟周期。表明,当data_en为高时,可将数据进行同步。本题中data_in端数据变化频率很低,相邻两个数据间的变化&…...

Unity UGUI的Shadow(阴影)组件的介绍及使用
Unity UGUI的Shadow(阴影)组件的介绍及使用 1. 什么是Shadow(阴影)组件? Shadow(阴影)组件是Unity UGUI中的一个特效组件,用于在UI元素上添加阴影效果。通过调整阴影的颜色、偏移、模糊等属性,可以使UI元素看起来更加立体和有层次感。 2. …...

Kubernetes系列
文章目录 1 详解docker,踏入容器大门1.1 引言1.2 初始docker1.3 docker安装1.4 docker 卸载1.5 docker 核心概念和底层原理1.5.1 核心概念1.5.2 docker底层原理 1.6 细说docker镜像1.6.1 镜像的常用命令 1.7 docker 容器1.8 docker 容器数据卷1.8.1 直接命令添加1.8.2 Dockerfi…...

同步锁: synchronized
synchronized 1. synchronized的特性2. synchronized的使用3. synchronized的锁机制 1. synchronized的特性 原子性: 所谓原子性就是指一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。可见性: 可见性是指多个线程…...

【微服务】springboot 多模块打包使用详解
目录 一、前言 1.1 为什么需要掌握多模块打包 二、工程模块概述 2.1 前后端不分离...

嵌入式工程师面试经常遇到的30个经典问题
很多同学说很害怕面试,看见面试官会露怯,怕自己的知识体系不完整,怕面试官考的问题回答不上了,所以今天为大家准备了嵌入式工程师面试经常遇到的30个经典问题,希望可以帮助大家提前准备,不再惧怕面试。 1&a…...

ER系列路由器多网段划分设置指南
ER系列路由器多网段划分设置指南 - TP-LINK 服务支持 TP-LINK ER系列路由器支持划分多网段,可以针对不同的LAN接口划分网段,即每一个或多个LAN接口对应一个网段;也可以通过一个LAN接口与支持划分802.1Q VLAN的交换机进行对接,实现…...

3 PostGIS基础查询
PostGIS 基础查询 数据库维护 ps aux | grep postgrespsql 使用命令登录数据库psql -U postgres -d testdb -h localhost -p 5432postgres用户名,testdb数据库名称,localhost ip地址,可以省略,5432端口,可以省略。 …...

Shell错误:/bin/bash^M: bad interpreter: No such file or directory
目录 错误原因和现象 解决方案 错误原因和现象 在执行shell脚本的时候,报错:/bin/bash^M: bad interpreter: No such file or directory。 是由于该脚本文件是在Windows平台编写,然后在MacOS平台中执行。 在Windows平台上文件是dos格式&…...

Golang之路---01 Golang的安装与配置
Golang之路—01 Golang语言安装与配置 官网上下载Windows环境下的安装包 官网下载地址 双击下载后的文件进行安装,可根据需要自定义选择解压后的文件位置。 接着新创建一个文件夹,保存Golang语言项目。 在里面新建bin,pkg,src三个文件夹。 环境变量…...

Anolis OS 8.8服务器采用docker容器方式搭建gerrit3.8.1服务
采用docker容器方式搭建gerrit3.8.1服务 一、选择管理帐户密码的方式二、部署gerrit服务1. 采用docker compose部署单服务的方式部分gerrit(1) docker-compose.yaml文件内容(2) 在docker-compose.yaml文件所在目录调用下面命令先进行初始化操作 2. 在宿主机上部署httpd服务用于…...

PyTorch 中的多 GPU 训练和梯度累积作为替代方案
动动发财的小手,点个赞吧! 在本文[1]中,我们将首先了解数据并行(DP)和分布式数据并行(DDP)算法之间的差异,然后我们将解释什么是梯度累积(GA),最后…...

Appium+python自动化(三十五)- 命令启动appium之 appium服务命令行参数(超详解)
简介 前边介绍的都是通过按钮点击启动按钮来启动appium服务,有的小伙伴或者童鞋们乍一听可能不信,或者会问如何通过命令行启动appium服务呢?且听一一道来。 一睹为快 其实相当的简单,不看不知道,一看吓一跳…...

vmware的window中安装GNS3
1.向vmware中的windows虚拟机传送文件 点击虚拟机-安装VMwaretools 安装在虚拟机上面 此图标代表已经成功,将文件复制到虚拟机上里面 2.安装 安装gns3,需要先安装winpcap(检查网卡)和wireshark(对winpcap上数据进行抓…...

FPGA XDMA 中断模式实现 PCIE3.0 AD7606采集 提供2套工程源码和QT上位机源码
目录 1、前言2、我已有的PCIE方案3、PCIE理论4、总体设计思路和方案AD7606数据采集和缓存XDMA简介XDMA中断模式QT上位机及其源码 5、vivado工程1--BRAM缓存6、vivado工程2--DDR4缓存7、上板调试验证8、福利:工程代码的获取 1、前言 PCIE(PCI Express&am…...

某某大学某学院后台Phar反序列化GetShell
觉得这个洞还算有点意思,可以记录一下 首先在另一个二级学院进行目录扫描时发现源码www.rar,并且通过一些页面测试推测这两个二级学院应该是使用了同一套CMS 分析源码,发现使用的是ThinkPHP 5.1.34 LTS框架 通过APP、Public得到后台访问路径…...

【ChatGPT辅助学Rust | 基础系列 | 基础语法】变量,数据类型,运算符,控制流
文章目录 简介:一,变量1,变量的定义2,变量的可变性3,变量的隐藏 二、数据类型1,标量类型2,复合类型 三,运算符1,算术运算符2,比较运算符3,逻辑运算…...

使用云服务器和Frp(快速反向代理)框架快速部署实现内网穿透
目录 一. 背景1.1 内网穿透1.2 Frp介绍1.3 Frp配置流程 二. 云服务器配置2.1 配置安全组2.2 编写frps.ini 三. 内网主机配置3.1 编辑frpc.ini文件3.2 启动服务并配置开机自启动 四. 参考文献 一. 背景 现在有一台ubuntu云服务器,我想通过内网穿透将一台内网的主机当…...

Mac 上使用 Tesseract OCR 识别图片文本
Tesseract OCR 引擎:Tesseract是一个开源的OCR引擎,你需要先安装它。可以从Tesseract官方网站(https://github.com/tesseract-ocr/tesseract)下载适用于你的操作系统的安装程序或源代码,并按照官方文档进行安装。 Tes…...

《MapboxGL 基础知识点》- 放大/缩小/定位/级别
中心点 getCenter:获取中心点 const {lng, lat} map.getCenter(); setCenter:设置中心点 // lng, lat map.setCenter([134, 28]); 缩放级别 getZoom:获取当前缩放级别 map.getZoom(); setZoom:设置缩放级别 map.setZoom(5…...

VScode的简单使用
一、VScode的安装 Visual Studio Code简称VS Code,是一款跨平台的、免费且开源的现代轻量级代码编辑器,支持几乎主流开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段提示、代码对比等特性,也拥有对git的开箱…...

# Unity 如何获取Texture 的内存大小
Unity 如何获取Texture 的内存大小 在Unity中,要获取Texture的内存文件大小,可以使用UnityEditor.TextureUtil类中的一些函数。这些函数提供了获取存储内存大小和运行时内存大小的方法。由于UnityEditor.TextureUtil是一个内部类,我们需要使…...

dolphinscheduler switch+传参无坑版
dolphinscheduler 的前后传参有较多的坑,即便是3.0.5版本仍然有一些bug 下面是目前能无坑在3.0.5版本上使用的操作 前置任务 在界面上设置变量和参数名称 跟官方网站不一样,注意最后一行一定使用echo ${setValue(key$query)}的方式,注意引…...

VINS-fusion安装
VINS-fusion中用的opencv3,如果安装的opencv4要做一系列替换 VINS-Mono在opencv4环境下的安装问题和解决方法 https://zhuanlan.zhihu.com/p/548140724 Vins-Fusion安装记录 https://zhuanlan.zhihu.com/p/432167383 CV_FONT_HERSHEY_SIMPLEX -> cv::FONT_HER…...

智慧消防:如何基于视频与智能分析技术搭建可视化风险预警平台?
一、背景分析 消防安全是一个重要的话题,涉及到每个人的生活和安全。每年都会发生大量的火灾,给人们带来极大的危害,摧毁了大量的财产,甚至造成了可怕的人员伤亡。而消防安全监督管理部门人员有限,消防安全监管缺乏有…...

selenium定位元素的方法
Selenium可以驱动浏览器完成各种操作,比如模拟点击等。要想操作一个元素,首先应该识别这个元素。人有各种的特征(属性),我们可以通过其特征找到人,如通过身份证号、姓名、家庭住址。同理,一个元…...