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], ...
随机推荐
- 微服务架构SpringCloud的理解
微服务架构是什么? 微服务是一种架构思想,实际上以分布式系统方式开发.架构是为了解耦.该架构解决的是分布式中的四个问题: 一.客户端如何访问众多服务: 应用划分为众多服务以后,客户端需要如何访问? 通 ...
- 老母鸡安装mqtt
大佬写好了, 按部就班操作一下就行了,在hass中添加mqtt可进行测试 玩客云搭建MQTT服务器 - 崔安兵 - 博客园 (cnblogs.com)
- armbian挂载sd卡记录
mkdir -p /mnt/mmctouch /etc/init.d/mount.shvim /etc/init.d/mount.sh内容见图mount /dev/mmcblk1p1 /mnt/mm ...
- elementui二维表动态渲染
elementUI如何动态渲染二维表,动态渲染表格的列,例如下图: 代码: <div id="app"> <template> <el-table : ...
- Maven 换源
~/.m2/settings.xml <settings> ... <mirrors> ... <mirror> <id>alimaven</id ...
- Kubernetes-1:初识k8s 什么是kubernetes
Kubernetes简介 为什么要用k8s? 容器间(Docker)在夸主机通信时,只能通过在主机做端口映射(DNAT)来实现,这种方式对于很多集群应用来说及其不方便.会影响整体处理速度,所以引入k8 ...
- CSS & JS Effect – Blue Tick Avatar
效果 难点 难题只有一个, 那就是如何把 blue tick image 定位当 avatar 的右下角. HTML <div class="avatar-wrapper"& ...
- ASP.NET Core – Partial View
前言 之前写过一篇 ASP.NET Core – View Component 里面有提到, View Component 是 Partial View 的加强版. 多了一个 .cs 可以写逻辑. 那 ...
- 课时05:Linux必备系统命令
- JS数据类型&类型转换
基本数据类型 JS中的数据类型由原始值和对象共同组成,原始值一共有七种原始值: 数值(Number) 大整数(BigInt) 字符串(String) 布尔值(Boolean) 空值(Null) 未定义 ...