JS 绘制 Cardinal 样条曲线
Cardinal 曲线
根据定义,给定点集 \(\{ \mathbf {P}_{k-1}, \mathbf {P}_k, \mathbf {P}_{k+1}, \mathbf {P}_{k+2} \}\) , 则 \(\mathbf {P}_k\) 到 \(\mathbf {P}_{k+1}\) 之间的 Cardinal 曲线可以由如下方程生成:
\mathbf{P}(u) & = \mathbf{a}u^3 + \mathbf{b}u^2 + \mathbf{c}u + \mathbf{d}\\
\mathbf{d} & =\mathbf {P}_k\\
\mathbf{c} & =s(\mathbf {P}_{k+1}-\mathbf {P}_{k-1})\\
\mathbf{b} & =3(\mathbf {P}_{k+1}-\mathbf {P}_k)-s(\mathbf {P}_{k+2}-\mathbf {P}_k)-2\mathbf{c}\\
\mathbf{a} & =(\mathbf {P}_{k+1}-\mathbf {P}_k) - \mathbf{c} - \mathbf{b}
\end {aligned}
\]
其中,\(s\) 用于控制曲线的松紧,取值范围为 [0, 1]。 0 表示最紧绷 (无平滑转角);1 表示最松弛。
绘制思路
根据公式,则只需将 \(u\) 从 0 到 1 采样并依据公式计算坐标即可。不过,由于不好把握 \(u\) 的采样间隔,这里并不打算采用这种方案。
我的思路是:
- 先计算两点之间 x, y 方向的差值
- 取差值绝对值较大的那个值,按预设精度进行细分,计算出 \(u\) 的步长
- 根据 \(u\) 的步长,计算方程的增量 \(\Delta \mathbf{P}\)
- 采用前向差分法,依次计算中间点坐标
a. 如果中间点到上一线段的距离小于预设精度,抛弃该点
前向差分
设有一个三次样条曲线,其表达式如下:
\]
如果将 \(u\) 的取值范围细分为具有固定大小 \(h\) 的子区间,则相邻两点 \(x\) 坐标为:
x_k &= x(u_k) \\
x_{k+1} &= x(u_k + h)
\end{aligned}
\]
可计算出前向差分为:
\Delta_1 x_k &= x_{k+1} - x_k \\
& = 3\mathbf {a} hu^2_k + (3\mathbf{a}h^2 + 2\mathbf{b}h)u_k + (\mathbf{a}h^3 + \mathbf{b}h^2 + \mathbf{c}h)
\end{aligned}
\]
由于 \(\Delta_1 x_k\) 是关于 \(u\) 的多项式,计算复杂,所以也可以计算出 \(\Delta_1 x_k\) 的增量 \(\Delta_2 x_k\),这样即可用加法计算出 \(\Delta_1 x_k\) 的值。不断重复计算增量的过程,直到增量为常数。最终可以得到:
\Delta_1 x_k &= 3\mathbf {a} hu^2_k + (3\mathbf{a}h^2 + 2\mathbf{b}h)u_k + (\mathbf{a}h^3 + \mathbf{b}h^2 + \mathbf{c}h) \\
\Delta_2 x_k &= 6\mathbf {a} h^2u_k +6\mathbf{a}h^3 + 2\mathbf{b}h^2\\
\Delta_3 x_k &= 6\mathbf{a}h^3
\end{aligned}
\]
根据以上公式,从 \(u_0=0\) 开始,步长为 \(h\),\(x\) 坐标的迭代过程为:
| \(k\) | \(\Delta_3 x_k\) | \(\Delta_2 x_k\) | \(\Delta_1 x_k\) | \(x_k\) |
|---|---|---|---|---|
| 0 | \(6\mathbf{a}h^3\) | \(6\mathbf{a}h^3 + 2\mathbf{b}h^2\) | \(\mathbf {a}h^3 + \mathbf {b}h^2 + \mathbf {c}h\) | \(\mathbf {d}\) |
| 1 | \(6\mathbf{a}h^3\) | \(\Delta_2 x_0 + \Delta_3 x_0\) | \(\Delta_1 x_0 + \Delta_2 x_0\) | \(x_0+\Delta_1 x_0\) |
| \(\vdots\) | ||||
| \(k\) | \(6\mathbf{a}h^3\) | \(\Delta_2 x_{k-1} + \Delta_3 x_{k-1}\) | \(\Delta_1 x_{k-1} + \Delta_2 x_{k-1}\) | \(x_{k-1} + \Delta x_{k-1}\) |
| 可以看到,每次迭代只需计算 3 次加法。 |
成果
最终效果如下图,也可以点击此处查看演示效果及源代码。

看起来效果还是不错的。不过,根据算法描述可以发现,如果两个点相距很近,就会因为中间点不够多而走样。
其它生成方法
当然还其它方法也可以绘制。比如,二分迭代法。每次计算出曲线的中点,将曲线按中点分为两部分,然后迭代这个过程。还可以先把曲线转换为 Bezier 曲线,然后进行绘制。
JS 绘制 Cardinal 样条曲线的更多相关文章
- Cardinal样条曲线的Javascript实现(理论篇)
首先,要对样条曲线进行插值的原因是:希望通过给定的关键帧点生成一条希望的直线或者曲线. 1.直线插值 生成一条直线,给定直线首尾的关键点P0,P1,就能确定这条直线的特性,比如y=kx+b中的斜率k和 ...
- 利用d3.js绘制雷达图
利用d3,js将数据可视化,能够做到数据与代码的分离.方便以后改动数据. 这次利用d3.js绘制了一个五维的雷达图.即将多个对象的五种属性在一张图上对照. 数据写入data.csv.数据类型写入typ ...
- 应用wavesurfer.js绘制音频波形图小白极速上手总结
一.简介 1.1 引 人生中第一份工作公司有语音识别业务,需要做一个web网页来整合语音引擎的标注结果和错误率等参数,并提供人工比对的语音标注功能(功能类似于TranscriberAG等),(博 ...
- js 绘制数学函数
<!-- <!doctype html> --> <html lang="en"> <head> <meta charset= ...
- JS 绘制心形线
JS 绘制心形线 <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> < ...
- QT绘制B样条曲线
² 贝塞尔曲线 贝塞尔曲线是通过一组多边折线的各顶点来定义.在各顶点中,曲线经过第一点和最后一点,其余各点则定义曲线的导数.阶次和形状.第一条和最后一条则表示曲线起点和终点的切线方向. ² B样条 ...
- Cardinal样条曲线的Javascript实现(代码篇)
由上一篇文章得到了Cardinal曲线的矩阵表达式,下面就这个矩阵表达式就可以来对曲线进行插值了. 这里选用了JS来实现,完全是因为之前交作业的时候还不知道怎么在Xcode里建完整的C++OpenGL ...
- ichart.js绘制虚线 ,平均分虚线
var Data=new Array(); Data[0] = { labels : ["第一单元","第二单元","第三单元"," ...
- Javascript实战开发:教你使用raphael.js绘制中国地图
最近的数据统计项目中要用到中国地图,也就是在地图上动态的显示某个时间段某个省份地区的统计数据,我们不需要flash,仅仅依靠raphael.js以及SVG图像就可以完成地图的交互操作.在本文中,我给大 ...
- d3.js 绘制极坐标图(polar plot)
0.引言 在极坐标系中,任意位置可由一个夹角和一段相对原点(极点)的距离表示.也就是说,我们可以用 (angle,r) 来表示极坐标系中的点. 1.数据 假设我们有如下数据集[ [10, 0.2], ...
随机推荐
- 一款.NET开发的AI无损放大工具
前言 今天大姚给大家分享一款由.NET开源(GPL-3.0 license).基于腾讯ARC Lab提供的Real-ESRGAN模型开发的AI无损放大工具:AI-Lossless-Zoomer. Re ...
- 【YashanDB知识库】自动选举配置错误引发的一系列问题
问题现象 问题出现的步骤/操作: 配置自动选举,数据库备库手动发起switch over,命令会报错 主.备库变为只读状态,数据库无法进行读写操作 shutdown immediate 停止数据库,此 ...
- 如何保证 Redis 的高并发和高可用?讨论redis的单点,高可用,集群
如何保证 Redis 的高并发和高可用?讨论redis的单点,高可用,集群. 打开GitHub搜索redis,边可以看到,该项目的介绍是这样的: Redis is an in-memory datab ...
- C++:使自定义类支持迭代器
概述 在 C++ 中,链表迭代器是一种用来遍历链表(如 std::list)元素的工具.链表是一种数据结构,其中每个元素(节点)包含一个数据值和一个指向下一个节点的指针.链表迭代器允许以类似于数组的方 ...
- 【QT界面美化】QT界面美化效果截图QSS+QML
贴几个QT做的界面美化效果截图. 先来一张动图,有一些画面是QT Widgets + QSS实现的:另外一些画面是QT QML实现的. QT界面美化效果图QT QSS QML 补天云QT技术培训专家 ...
- vscode单行注释失效解决办法
第一种情况: bug:在使用快捷键注释的时候,只有style和script标签里的内容注释有问题,无法使用快捷键注释. 解决方法:禁用vscode的插件Jinja. 第二种情况 方法一 1.Ctrl+ ...
- 30. 串联所有单词的子串 Golang实现
题目描述: 给定一个字符串 s 和一个字符串数组 words. words 中所有字符串 长度相同 . s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串. 例如, ...
- LNMP 和 LAMP 对比 (仅供参考)
Nginx 性能稳定.功能丰富.运维简单.处理静态文件速度快且消耗系统资源极少. Apache 是 LAMP 架构最核心的 Web Server,开源.稳定.模块丰富是 Apache 的优势.但 Ap ...
- 手搓大模型Task03:手搓一个最小的 Agent 系统
前言 训练一个大模型是一件高投入低回报的事情,况且训练的事情是由大的巨头公司来做的事情:通常我们是在已有的大模型基础之上做微调或Agent等:大模型的能力是毋庸置疑的,但大模型在一些实时的问题上, ...
- 为什么用 AWS CLI?因为我懒得点鼠标!
在这篇博客中,我们一起深入探索 AWS CLI 的世界,从零开始,逐步构建在云端的家园.将介绍 AWS CLI 的基本功能和使用场景,如何创建 IAM 用户.VPC.子网.安全组.EC2 实例等,甚至 ...