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], ...
随机推荐
- 代码随想录Day12
二叉树遍历 分为前序.中序.后续.层序四种 其中前中后序属于深度优先搜索,层序属于广度优先搜索 前序遍历顺序: 根节点->左子树->右子树 中序遍历顺序: 左子树->根节点-> ...
- SMU Spring 2023 Contest Round 7
A. Programming Contest 签到题. 输入输出读完应该就懂了: 从y1枚举到y2,若枚举的年份不在停办年份里则答案加一 void solve() { int n,m; cin > ...
- 【牛客刷题】HJ10 字符个数统计
题目链接 简单的说这题就是字符串去重以后检查长度.如果用Java的话,可以遍历字符串,然后利用Set来进行去重,最后统计Set的size就可以了.但是如果是Go语言,则稍微麻烦点.基本思路就是用map ...
- Camera | 4.瑞芯微平台MIPI摄像头应用程序编写
前面3篇我们讲解了camera的基础概念,MIPI协议,CSI2,常用命令等,本文带领大家入门,如何用c语言编写应用程序来操作摄像头. Linux下摄像头驱动都是基于v4l2架构,要基于该架构编写摄像 ...
- Kubernetes-8:Deployment、DaemonSet、Job、CronJob等各控制器介绍及演示
前文中也都已经提及过k8s都有哪些常用的控制器,本文对这些控制器进行细剖及演示一下 RS与RC与Deployment关联 RC主要作用就是用来确保容器应用副本数保持用户的期望值数目,即如果有pod异常 ...
- 【转】ElasticSearch报错FORBIDDEN/12/index read-only / allow delete (api) ,read_only_allow_delete 设置 windows
仅供自己记录使用,原文链接:ElasticSearch报错FORBIDDEN/12/index read-only / allow delete (api)_sinat_22387459的博客-CSD ...
- 【YashanDB知识库】ODBC驱动类问题定位方法
[标题]ODBC驱动类问题定位方法 [需求分类]故障分析 [关键字]ODBC [需求描述]由于我们的ODBC接口目前尚不完善,经常会遇见ODBC接口能力不足导致应用功能无法运行的问题,需要定位手段确定 ...
- C#自定义控件—仪表盘
C#用户控件之仪表盘 如何让温度.湿度.压力等有量程的监控值如仪表盘(DashBoard)一样显示? 思路(GDI绘图): 定义属性:(仪表盘的半径.颜色.间隙:刻度圆的半径.颜色.字体:指针的颜色. ...
- 海光 FTPM 运行报错:Fapi_Provision_Finish() ErrorCode (0x00060025) No EK certificate found.
使用的是海光 CPU 提供的基于固件的 FTPM,错误原因是海光没有给 TPM 提供相应的 EK 证书.从而导致Fapi_Provision()接口无法通过证书的校验.关于Fapi_Provision ...
- JSP——简介-快速入门
JSP 简介 JSP 快速入门 <%@ page contentType="text/html;charset=UTF-8" language=&qu ...