最近看到 写 Rust 函数,免费树莓派 的活动,便了解了一下 SSVM, 对我来说 ssvmup 与 wasm-pack 相比最方便的一点是:

除了在 Rust 和 JavaScript 之间传递字符串值外,ssvmup 工具还支持以下数据类型。

  • Rust 调用的参数可以是 i32String&strVec<u8> 和&[u8] 的任意组合
  • 返回值可以是 i32 或 String 或 Vec<u8>
  • 对于像结构这样的复杂数据类型,可以使用 JSON 字符串传递数据

对 Vec<u8> 的支持可以不用再 通过 buffer + pointer 的方式共享数据,使用起来非常方便。

万花尺

万花尺原理:

万花尺轨迹性质研究  https://blog.csdn.net/qq_37613112/article/details/106100651

利用三角函数绘制万花尺图案属于计算较多的场景了,这里实现的 Rust 函数为:绘制万花尺图案并编码为 PNG 格式。

其实这个场景更适合在 web 端完成,绘制好的图案不用编码直接作为 canvas 数据展示,更加高效。

这里为了体验 SSVM ,把 Rust 函数编译为 wasm 后供 nodejs 调用,在服务端生成图片返给 web 端。

最终效果

功能实现

万花尺图案绘制相关的参数有:大圆半径、小圆半径、绘制点到小圆圆心的距离、当前小圆顺大圆转动的角度 alpha、小圆自转的角度 beta 、以及画笔颜色。

此处将小圆运动相关上下文抽象为结构体 Pannel, 为其实现 2 个方法:

  1. 移动:小圆顺着大圆滚动指定的角度 delta,更新 alpha 和 beta。不断以较小值的 delta 移动小圆,便是对其运动的模拟
  2. 计算当前画笔位置:随着小圆的运动,画笔位置也在不断变化,其轨迹最终形成图案

代码如下:

struct Pannel {outer_r: f64,inner_r: f64,distance: f64,alpha: f64,beta: f64,
}
impl Pannel {fn step(&mut self, alpha_delta: f64) -> (f64, f64) {self.alpha += alpha_delta;let a = alpha_delta * self.outer_r;let beta_delta = a / self.inner_r;self.beta += beta_delta;self.current_pos()}#[inline]fn current_pos(&self) -> (f64, f64) {let a = self.beta - self.alpha;let delta_y = a.sin() * self.distance;let delta_x = a.cos() * self.distance;let center_y = self.alpha.sin() * (self.outer_r - self.inner_r);let center_x = self.alpha.cos() * (self.outer_r - self.inner_r);let x = center_x - delta_x;let y = center_y - delta_y;(x, y)}
}

有了线条的轨迹,便可以作图,具体绘制函数如下:

#[wasm_bindgen]
pub fn draw(outer_r: u32,inner_r: u32,dist: u32,square_size: u32,r: u8,g: u8,blue: u8,
) -> Vec<u8> {let b = blue;let outer_r = outer_r as f64;let inner_r = inner_r as f64;let dist = dist as f64;let mut p = Pannel {outer_r,inner_r,distance: dist,alpha: 0.0,beta: 0.0,};let mut square = Square::new_img(square_size);let step = std::f64::consts::PI / 720.0;for _ in 0..72000 {let (x, y) = p.step(step);square.set_point(x, y, r, g, b, 255);}square.into_data()// unsafe {//     BUFFER = square.into_data();//     BUFFER.as_ptr()// }
}

绘制函数中用到的 Square 是枚举类型,其实现如下:

enum Square {Canvas(Vec<u8>, usize),Img(image::DynamicImage, u32),
}impl Square {fn new_canvas(size: usize) -> Square {Square::Canvas(vec![0u8; size * size * 4], size)}fn new_img(size: u32) -> Square {Square::Img(image::DynamicImage::new_rgba8(size, size), size)}fn set_point(&mut self, x: f64, y: f64, r: u8, g: u8, b: u8, a: u8) {let size = match self {Square::Canvas(_, size) => *size as isize,Square::Img(_, size) => *size as isize,};let center = size / 2;let mut x = (x as isize) + center;let mut y = (y as isize) + center;if x < 0 {x = 0;};if y < 0 {y = 0;};if x >= size {x = size - 1};if y >= size {y = size - 1};match self {Square::Canvas(meta, _) => {let idx = (x * y * 4) as usize;meta[idx] = r;meta[idx+1] = g;meta[idx+2] = b;meta[idx+3] = a;}Square::Img(img, _) => img.put_pixel(x as u32, y as u32, image::Rgba([r, g, b, a])),}}fn into_data(self) -> Vec<u8> {match self {Square::Canvas(meta, _) => meta,Square::Img(img, _) => {let mut data = vec![];{let mut buf = std::io::BufWriter::new(&mut data);let _ = img.write_to(&mut buf, image::ImageFormat::Png);}data}}}
}

至此, Rust 部分已全部完成,接下来,通过 ssvmup 生成对应的 wasm 代码,而后在 nodejs 中使用:

const { draw } = require('../pkg/ssvm_nodejs_starter_lib.js');
const buffer = require('buffer');
var fs = require("fs");const http = require('http');
const url = require('url');
const hostname = '0.0.0.0';
const port = 3000;const server = http.createServer((req, res) => {const u = url.parse(req.url,true);const queryObject = u.query;const action = u.pathname;if (action == '/draw') {outer_r = parseInt(queryObject['outer_r'])inner_r = parseInt(queryObject['inner_r'])dist = parseInt(queryObject['dist'])square_size = parseInt(queryObject['square_size'])r = parseInt(queryObject['r'])g = parseInt(queryObject['g'])blue = parseInt(queryObject['b'])var img = draw(outer_r, inner_r, dist, square_size, r, g, blue);res.writeHead(200, {'Content-Type': 'image/png' });res.end(buffer.transcode(img, 'binary', 'binary'), 'binary');return;}fs.readFile("index.html", function(err, data){res.writeHead(200, {'Content-Type': 'text/html'});res.write(data);res.end();});
});server.listen(port, hostname, () => {console.log(`Server running at http://${hostname}:${port}/`);
});

用于展示结果的页面内容如下:

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Hypocycloid</title><script>function refresh(){var o = document.getElementById('outer_r').value;var i = document.getElementById('inner_r').value;var d = document.getElementById('dist').value;var s = document.getElementById('square_size').value;var r = document.getElementById('red').value;var g = document.getElementById('green').value;var b = document.getElementById('blue').value;var src = `/draw?outer_r=${o}&inner_r=${i}&dist=${d}&square_size=${s}&r=${r}&g=${g}&b=${b}`;document.getElementById('image').src = src;}</script>
</head>
<body>
大圆半径: <input type="number" id="outer_r" value="100"><br>
小圆半径: <input type="number" id="inner_r" value="8"><br>
绘制点到小圆圆心距离: <input type="number" id="dist" value="60"><br>
画布边长: <input type="number" id="square_size" value="360"><br>
R: <input type="number" id="red" value="0"><br>
G: <input type="number" id="green" value="255"><br>
B: <input type="number" id="blue" value="0"><br>
<input type="button" value="提交" onclick="refresh()">
<img src="/draw?outer_r=100&inner_r=8&dist=60&square_size=360&r=20&g=250&b=0" id="image"/>
</body>
</html>

Hello SSVM: 利用 SSVM + wasm 实现万花尺图案的绘制相关推荐

  1. python教程长城图案,Python编写万花尺图案实例

    小的时候大家应该都玩过万花尺,将笔尖放置万花尺内不停的转动,便可以画出一幅精致的线稿图,现在我们不用万花尺,我们通过Python也能绘制出万花尺图案. (一)代码 #!/usr/bin/python# ...

  2. python绘制花朵图案_Python编写万花尺图案实例

    小的时候大家应该都玩过万花尺,将笔尖放置万花尺内不停的转动,便可以画出一幅精致的线稿图,现在我们不用万花尺,我们通过Python也能绘制出万花尺图案. (一)代码 #!/usr/bin/python# ...

  3. 利用单片机控制74HC595显示图案

    利用单片机控制74HC595显示图案(单片机型号STC89C52) 此文将介绍如何用74HC595自定义显示图案,需要一定的单片机学习基础,话不多说,上代码 #include "reg51. ...

  4. Matlab绘图基础——利用axes(坐标系图形对象)绘制重叠图像 及 一图多轴(一幅图绘制多个坐标轴)

    Matlab绘图基础--利用axes(坐标系图形对象)绘制重叠图像 及 一图多轴(一幅图绘制多个坐标轴) - 司徒鲜生 - 博客园 Matlab中axes函数解析_ljh0302的博客-CSDN博客_ ...

  5. matlab画三维图电磁场,利用matlab实现矩形波导电磁场分布图的绘制.doc

    利用matlab实现矩形波导电磁场分布图的绘制.doc 利用MATLAB实现矩形波导电磁场分布图的绘制(附源程序)通过MATLAB计算并绘出任意时刻金属矩形波导的主模TE10模的电磁场分布图.波导尺寸 ...

  6. 利用MATLAB对数据进行切片并绘制图表

    利用MATLAB对数据进行切片并绘制图表 文章目录 利用MATLAB对数据进行切片并绘制图表 1 读取txt文件 2 对矩阵进行切片,提取信息 3 使用MATLAB绘图 4 附录--完整代码 1 读取 ...

  7. 分别用Java应用程序和Applet程序实现星星三角形图案的绘制

    一,用Java应用程序和Applet程序实现星星三角形图案的绘制 1,新建java project , project name 为 Triangle 2,新建new class , class na ...

  8. matlab电磁场图像如何画,利用matlab实现矩形波导电磁场分布图的绘制

    利用matlab实现矩形波导电磁场分布图的绘制 利用 Matlab 实现矩形波导电磁场分布图的绘制(附源程序)通过 Matlab 计算并绘出任意时刻金属矩形波导的主模 TE10 模的电磁场分布图.波导 ...

  9. C++编程练习 利用嵌套循环实现各类三角形图案

    原题来自菜鸟教程 C++ 实例 - 创建各类三角形图案 文章目录 1.*组成的直角三角形 2.数字组成的三角形 3.字母组成的三角形 4.打印*组成的倒三角 5.打印数字组成的倒三角形 6.*构成的金 ...

最新文章

  1. 判断线程是否执行完毕_Java并发编程 | 线程核心机制,基础概念扩展
  2. Python学习笔记:高级特性
  3. C语言ODBC方式连接DM数据库
  4. python爬取数据
  5. JavaScript 常用代码整理
  6. git 删除本地和远程分支_如何在本地和远程删除Git分支
  7. docker实践第二版pdf 网盘_【漫画】什么是 docker?docker 应用场景解析
  8. JavaScript从父页面获取子页面的值(子页面又如何访问父页面)
  9. 系统日期oracle,oracle系统函数(日期函数)
  10. jQuery中点击按钮创建表格
  11. 使用python获取vCenter默认警报定义
  12. Python 操作 Word
  13. Android按键音
  14. 【2】Kali破解家用WI-FI密码 - WPA/WPA2加密
  15. resultMap使用不当导致出现There is no WRITEABLE property named 'student_id' in class 'com.ssi.model.Stud
  16. 前方高能,这个语音转文字转换器超实用
  17. 时尚手表品牌PaulHewitt,手表手链超时尚品牌礼物
  18. 常见内网穿透-花生壳、神卓互联、FRP、ngork分析
  19. seek 方法java,Seek.java
  20. 14.利用虚函数实现多态性来求正方体、球体和圆柱体的表面积和体积。

热门文章

  1. 三级网络技术之:网络安全技术
  2. fh511小风扇主控芯片 便携式小风扇专用8脚IC 三档小风扇升压芯片sop8
  3. 一个数据分析师的自我修养
  4. Linux中的soft和hard limit
  5. 轻型笔记软件 CherryTree
  6. Parallels Desktop分享:文件夹共享技巧
  7. Windows下安装图片标注工具LabelImg遇到的问题及解决办法
  8. MGRE下的OSPF实验
  9. 玩游戏也能赚钱?还有这种操作?
  10. 使用路由器中碰到的问题总结