为什么要写这篇文章
本篇接《张侦毅:巴恩斯利蕨数学公式及源码实现》。之前文章中源码的编程语言用的是Java,JDK的版本为8,现在我的JDK版本已经升级到22了,在新版本JDK中,原来的JApplet方法已经被废弃,不能用了。
在JDK22中的说明是这样的:
上面内容主要是说Java中的JApplet类自从JDK9已经被废弃,不能用了,因而我们在画巴恩斯利蕨时,就应该考虑换一种编程语言,恰好我很擅长JavaScript,所以就将用Java写的巴恩斯利蕨替换成了用JavaScrip写的版本(很多从事后端的程序开发者至少都会两种及以上的编程语言,我这也不例外,所以可以在至少两种编程语言间随意切换)。
巴恩斯利蕨数学公式
巴恩斯利蕨数学公式见下图:
巴恩斯利蕨源码实现
<!DOCTYPE html>
<html lang="zh">
<head>
<title>巴恩斯利蕨</title>
<meta charset="UTF-8">
</head>
<body>
<canvas id="myCanvas" width="700" height="700" style="border:1px solid #996633;"></canvas>
<script type="text/javascript">
// 获取页面canvas节点
const canvas = document.getElementById('myCanvas');
// 背景颜色设置为黑色
canvas.style.backgroundColor = "black";
// 平面画图
const ctx = canvas.getContext('2d');
// 叶片颜色设置为绿色
ctx.strokeStyle = "green";
// 线条宽度
ctx.lineWidth = 0.1;
// 叶片位置
const offsetX = 320, offsetY = -170;
// 缓存数据
let x2 = 0, y2 = 0;
// 像素数目
const pixelCounts = 4000000;
// 图片放大倍数
const mag = 56;
// 图像翻转
const overturnY = 400;
// 函数出现概率
const f1 = 1, f2 = 85,f3 = 7;
// 定义map的键值对
const X = "x",Y = "y";
// 创建Map容器
let map = new Map(),temp = new Map(); // 代替之前的entry
/**
* 图像上下翻转
*/
function overturn(){
y2 = y2 - (y2 - overturnY) * 2;
}
/**
* 原图片计算数据为厘米,而我的绘图,单位却是像素,因而需要根据自己电脑需求,将厘米转换为像素
* @param map 容器
*/
function magnification(map){
x2 = map.get(X) * mag;
y2 = map.get(Y) * mag;
}
/**
* 方程func4
* @param map 容器
*/
function func4(map){
x = -0.15 * map.get(X) + 0.28 * map.get(Y);
y = 0.26 * map.get(X) + 0.24 * map.get(Y) + 0.44;
temp.set(X,x);
temp.set(Y,y);
deepCopy(map,temp);
}
/**
* 方程func3
* @param map 容器
*/
function func3(map){
x = 0.2 * map.get(X) - 0.26 * map.get(Y);
y = 0.23 * map.get(X) + 0.22 * map.get(Y) + 1.6;
temp.set(X,x);
temp.set(Y,y);
deepCopy(map,temp);
}
/**
* 方程func2
* @param map 容器
*/
function func2(map){
x = 0.85 * map.get(X) + 0.04 * map.get(Y);
y = -0.04 * map.get(X) + 0.85 * map.get(Y) + 1.6;
temp.set(X,x);
temp.set(Y,y);
deepCopy(map,temp);
}
/**
* 深度复制
* @param map 拷贝目的地
* @param temp 源数据
*/
function deepCopy(map,temp){
map.set(X,temp.get(X));
map.set(Y,temp.get(Y));
}
/**
* 方程 func1
* @param map
*/
function func1(map){
temp.set(X,0);
temp.set(Y,0.16 * map.get(Y));
deepCopy(map,temp);
}
/**
* 画巴恩斯利蕨
*/
function drawBarnsleyFern() {
map.set(X,0);
map.set(Y,0);
// 像素数目
for(let i = 0; i < pixelCounts; i ++){
// 生成随机数(Math.random()生成大于等于 0.0 且小于 1.0 的伪随机 double 值,
// 故在生成的数字后面 * 99,再 + 1,才是1 - 100的随机数)
const randomNumber = Number.parseInt(Math.random() * 99 + 1);
// 选择函数公式
if(randomNumber === f1){
// 主干
func1(map);
} else if(randomNumber > f1 && randomNumber <= (f1 + f2) ){
// 叶片
func2(map);
} else if(randomNumber > (f1 + f2) && randomNumber <= (f1 + f2 + f3)){
// 左侧树叶
func3(map);
} else {
// 右侧树叶
func4(map);
}
// 将原图像数据按比例尺放大
magnification(map);
// 图像翻转
overturn();
// 开始绘制路径
ctx.beginPath();
// 画点(也就是画圆)
ctx.moveTo(x2 + offsetX, y2 + offsetY);
ctx.lineTo(x2 + offsetX + 1, y2 + offsetY + 1);
// 绘图
ctx.stroke();
}
}
// 画巴恩斯利蕨
drawBarnsleyFern();
</script>
</body>
</html>
效果图
这是图片截图:
这是高清png图:
图片更加的高清
该JavaScrip版本的巴恩斯利蕨与之前的Java版本在画质精度上有着明显的提升,具体表现在两点上:
1、线条点的宽度更小
Java版本的巴恩斯利蕨线条宽度为1,而在JavaScrip版本中,该线条宽度则为0.1。更小的线条宽度意味着,在原有图片像素点不变的前提下,该图片显得更透明,尤其是在画布背景颜色调成黑色后,这样的巴恩斯利蕨图片看上去更暗淡。
2、巴恩斯利蕨的像素点数更多
在原Java版本的巴恩斯利蕨中,该像素点数量为200000,而在新版的JavaScrip版本中,该像素点的数量为4000000。相较于前一个版本,新版本的像素点数量直接提升了20倍!所以JavaScrip版的巴恩斯利蕨相较于Java版本图片而言,清晰度提升了20倍!
更小的线条宽度,更高的像素点数量,这意味着该版本的巴恩斯利蕨相较于前一个版本而言,画质获得了质的提升。
注:该文章来自《巴恩斯利蕨数学公式及源码实现——JavaScript版》,作者是同人,所以属于原创。