.NET 模拟&编辑平滑曲线
本文介绍不依赖贝塞尔曲线,如何绘制一条平滑曲线,用于解决无贝塞尔控制点的情况下绘制曲线、但数据点不在贝塞尔曲线的场景。
在上一家公司我做过一个平滑曲线编辑工具,用于轮椅调整加减速曲线。基于几个用户可控制的点,生成一条平滑的曲线,控制点需要保持在曲线上。
今天和小伙伴沟通,白板的形状绘制笔迹,也可以使用到这个技术,所以需要回顾总结下
贝塞尔平滑曲线
我们先讲贝塞尔曲线GDI+ 中的贝塞尔自由绘制曲线 - Windows Forms .NET Framework | Microsoft Learn。一般情况我们绘制平滑曲线,直接以贝塞尔曲线API将多个点作为参数,直接进行绘制。这种情况下API会自动将第一个点作为控制点,得到贝塞尔曲线,比如下面生成一条平滑Geometry:
1 var geometryTest = new StreamGeometry();
2 using(var ctx = geometryTest.Open())
3 {
4 ctx.BeginFigure(_points[0], true, false);
5 if(keyPoints.Count % 2 == 0)
6 {
7 //绘制二阶贝塞尔函数,需要保证为偶数点
8 ctx.PolyQuadraticBezierTo(keyPoints, true, true);
9 }
10 else
11 {
12 //绘制二阶贝塞尔函数,需要保证为偶数点
13 keyPoints.Insert(0, keyPoints[0]);
14 ctx.PolyQuadraticBezierTo(keyPoints, true, true);
15 }
16 }
这里的PolyQuadraticBezierTo函数,塞点集列表进去并设置平滑参数isSmoothJoin=true
1 public abstract void PolyQuadraticBezierTo(
2 IList<Point> points,
3 bool isStroked,
4 bool isSmoothJoin);
5
6 public abstract void PolyBezierTo(IList<Point> points, bool isStroked, bool isSmoothJoin);
官网有介绍,列表中第一个点作为控制点:StreamGeometryContext.PolyQuadraticBezierTo 方法 (System.Windows.Media) |Microsoft 学习
上面是自动设置控制点,这类实现方案会有一个问题:数据点最终可能不在曲线上
基于贝塞尔曲线,我们也可以计算控制点。但计算控制点,也是同样无法保证原始数据点会在拟合后的曲线上。
模拟平滑曲线
以现有数据点,如果直接相连肯定只会生成多个折线。如果我们添加多个点,可以模拟一条类似曲线路径的多边形近似点集,与Geometry下的FlattenedPathGeometry有点类似。
方案一,可以使用MathNet.Numerics生成一条X方向的N阶曲线,然后输入X坐标输出Y坐标,得到曲线上的点。 MathNet.Numerics可以参考 .NET 白板书写加速-曲线拟合预测 - 唐宋元明清2188 - 博客园。但这方案会生成无数点,曲线绘制性能无法得到保证。所以添加这些曲线路径的点,如何以最小的点集实现?可以对相邻点,对向量角度变化以及相邻间距设置一个最小阈值,最终得到符合的点集
方案二,用我之前实现方案,根据最简多项式代码算出近似样条曲线点集。原理同MathNet.Numerics里的Polynomial函数,下面是部分代码:
1 private const double Tolerance = 0.5;
2
3 /// <summary>
4 /// 获取拟合后的点集
5 /// </summary>
6 /// <param name="points"></param>
7 /// <returns></returns>
8 public static List<Point> GetFittingLinePoints(List<Point> points)
9 {
10 var orderedPoints = (from pt in points orderby pt.X select pt).ToList();
11 var secondDerivatives = SecondDerivativeHelper.GetSecondDerivatives(orderedPoints);
12 List<Point> polyLinePoints = PointFakeApproximationHelper.GetSplinePolyLineApproximation(orderedPoints, secondDerivatives, Tolerance);
13 return polyLinePoints;
14 }
获取俩点之间点集:
1 /// <summary>
2 /// 用折线逼近三次多项式并给出公差。
3 /// </summary>
4 /// <param name="leftPoint">三次多项式左点</param>
5 /// <param name="rightPoint">三次多项式右点</param>
6 /// <param name="secondDerivativeLeft">左点三次多项式二阶导数.</param>
7 /// <param name="secondDerivativeRight">右端三次多项式二阶导数.</param>
8 /// <param name="tolerance">公差,即样条到近似折线的最大距离。</param>
9 /// <returns>在给定公差的情况下逼近三次多项式的多边形点的列表。</returns>
10 private static Collection<Point> GetApproximation(Point leftPoint, Point rightPoint, double secondDerivativeLeft, double secondDerivativeRight, double tolerance)
11 {
12 // 左右俩点的X、Y轴值
13 double leftPointX = leftPoint.X, rightPointX = rightPoint.X;
14 double leftPointY = leftPoint.Y, rightPointY = rightPoint.Y;
15 // 次区间多项式系数
16 double a = (secondDerivativeRight - secondDerivativeLeft) / (6 * (rightPointX - leftPointX));
17 double b = (secondDerivativeLeft - 6 * a * leftPointX) / 2;
18 double c = (rightPointY - rightPointX * rightPointX * (a * rightPointX + b) - leftPointY + leftPointX * leftPointX * (a * leftPointX + b)) / (rightPointX - leftPointX);
19 double d = leftPointY - leftPointX * (leftPointX * (a * leftPointX + b) + c);
20
21 //如果a的值为0,则给a赋值double类型的最小正数
22 if(a == 0)
23 a = double.Epsilon;
24
25 //通过多项式与拆线的逼近,获取多边形点的列表
26 Collection<Point> points = CubicPolynomialPolylineApproximation.Approximate(new Polynomial(new double[] { d, c, b, a }), leftPointX, rightPointX, tolerance);
27 return points;
28 }
效果如下图,左侧是原数据点集(绿色),右则截图是模拟后的点集显示(红色):
把这些新增点与原数据点,用直接连接起来,就是一条比较平滑的曲线了。同时原数据点也在拟合的曲线上。另外,如果还需要优化下这些线段的平滑,可以使用贝塞尔曲线替换直线连接,已经加了很多密集点,绿点不会脱离曲线的。
Github仓库代码 GitHub - kybs00/CurveLineEditDemo: 平滑曲线模拟及编辑Demo
编辑平滑曲线
上面我们已经完成了平滑曲线的点集模拟,连接起来就是一条曲线。在一些业务场景中,需要以曲线上的点为控制操作点,移动点以达到编辑曲线。
在曲线上设置多个操作点。如何在曲线上设置期望位置的点,可以看 .NET 曲线上的点- 获取距离最近的点 - 唐宋元明清2188 - 博客园。点击时,获取曲线离点击位置最近的点即可
选择点后,操作控制点移动。曲线根据操作点的位置变更,重新生成新的曲线。曲线编辑效果如下图:
重新生成曲线这部分代码没有啥难点,核心代码就是上面的平滑曲线模拟。看上面仓库代码即可
参考文章:
GDI+ 中的贝塞尔自由绘制曲线 - Windows Forms .NET Framework | Microsoft Learn
Bezier曲线反求控制点_如何反求贝塞尔曲线的控制点-CSDN博客
.NET 模拟&编辑平滑曲线的更多相关文章
- Vue+Mock.js模拟登录和表格的增删改查
有三类人不适合此篇文章: "喜欢站在道德制高点的圣母婊" -- 适合去教堂 "无理取闹的键盘侠" -- 国际新闻版块欢迎你去 "有一定基础但又喜欢逼逼 ...
- 更换Mac记录
1. 重装Mac (1)格式化硬盘 (2)重装系统 (3)修改各种配置:电脑名.键盘等 2. 安装必要软件 (1)QQ.微信.网易云音乐等 (2)火狐.谷歌.SourceTree等 (3)安装Git ...
- Adobe Audition音频制作
Adobe Audition 同义词 AU(软件(Adobe Audition))一般指Adobe Audition Adobe Audition是一个专业音频编辑和混合环境,原名为Cool Edit ...
- CodeSnippet.info 开源说明 和 环境搭建 (第一版)
Github开源声明 本网站的代码开源,开源的目的如下 技术分享 希望业内同行贡献代码 希望能够让网站更加安全 开源地址: CodeSnippet开源地址 关于代码贡献 任何人都可以贡献代码,一般在 ...
- 恶意软件/BOT/C2隐蔽上线方式研究
catalogue . 传统木马上线方式 . 新型木马上线方式 . QQ昵称上线 . QQ空间资料上线 . 第三方域名上线 . UDP/TCP二阶段混合上线 . Gmail CNC . NetBot两 ...
- IIS7 ASP.NET 未被授权访问所请求的资源
IIS7 ASP.NET 未被授权访问所请求的资源 ASP.NET 未被授权访问所请求的资源.请考虑授予 ASP.NET 请求标识访问此资源的权限. ASP.NET 有一个在应用程序没有模拟时使用的基 ...
- 基于 Jenkins 构建持续集成任务
1.1 Jenkins 配置使用心得 我是在windows10上安装的,安装过程很简单,从官网上下载下来msi安装包,双击执行就好了.安装程序完成后会自动打开http://localhost:8080 ...
- SpringMVC项目
一.说明该项目是为了演示SpringMVC框架中涉及到的一些知识点,相对独立,掌握这些,基本上就能够解决工作中遇到的一些问题.整个项目的构建规划如下: 1.创建一个标准的Maven Web项目;2.使 ...
- Ng-Alain-mock 运用
Ng-Alain Ng-Alian 是基于 Antd 实现的一个前端框架.它基于 Angular 和 NG-ZORRO,在此基础上进行进一步封装,是中后台的前端解决方案,为我们提供更多通用性业务模块, ...
- Css+JS模拟实现可编辑的表格
表格在未编辑状态和编辑状态,需要定义两个不同的样式. 比如未编辑状态是lable的样式,两边有两个括号[],表示该表格可以编辑:编辑中的表格则表示成一个input框,可以输入. 基本思路就是,在表格中 ...
随机推荐
- @vue/cli typescript插件使用指南
步骤 使用 yarn add 安装 @vue/cli-service 对应版本的 @vue/cli-plugin-typescript 例如:"@vue/cli-service": ...
- QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于QWindow的? 如何实现QT框架栅格窗口?如何实现QT框架OpenGL窗口?
QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于QWindow的? 如何实现QT框架栅格窗口?如何实现QT框架OpenGL窗口? 简介 本文介绍了QT6窗口系统中的QT底层窗口 ...
- [TK] BLO
初步分析 此题描述让我们想到Tarjan求割点,因此我们从割点的角度来探讨一下这道题. 假如我们去掉的不是一个割点,那么它实际上不会对连通性造成影响,但是根据样例可以看出来,删去这个点导致了其余点与当 ...
- Win11本地部署FaceFusion3最强AI换脸,集成Tensorrt10.4推理加速,让甜品显卡也能发挥生产力
FaceFusion3.0.0大抵是现在最强的AI换脸项目,分享一下如何在Win11系统,基于最新的cuda12.6配合最新的cudnn9.4本地部署FaceFusion3.0.0项目,并且搭配Ten ...
- 解决 -Code 安装似乎损坏。请重新安装
问题: 1. 安装插件 fix VSCode Checksums 2. ctrl+shift+P打开命令面板 3. 输入 Fix Checksums: Apply 4. 重新启动VSCode
- 关于使用plsql操作oracle的一点小技巧和几个常用的查询语句
plsql是什么: 就是这个,专门操作oracle的一个工具,好用还免费. 创建一个测试表: create table Student( Id number not null, Name varcha ...
- 在不需要WiFi密码的情况下进行断网攻击
本教程只能用于学习研究之用 任何未经他人允许的攻击行为都是违法行为 参考教程 https://www.youtube.com/davidbombal 准备 * kali linux 系统 这里使用的是 ...
- 探索 Kubernetes 持久化存储之 Rook Ceph 初窥门径
在 Kubernetes 生态系统中,持久化存储是支撑业务应用稳定运行的基石,对于维护整个系统的健壮性至关重要.对于选择自主搭建 Kubernetes 集群的运维架构师来说,挑选合适的后端持久化存储解 ...
- 关于git的安装
window平台下面: 步骤一: 首先去官网下载安装包: 官方链接:https://git-scm.com/download/win 至于选择32位还是64为的,各位就见仁见智了(根据自己的系统). ...
- cxv文件合并
1.新建bat脚本 @echo off setlocal enabledelayedexpansion copy *.csv new.csv echo @@@@@@@@@@@@@合并成功!@@@@@@ ...