真实世界是不完美的,当我们需要模拟真实世界时,经常需要引入不完美/不规则的形状。比如陨石、雨滴、行星、树叶、绵延的海岸线、云朵等。

本文介绍如何基于Canvas生成随机大小的不完美圆形,所用方法适用于很多场合,一个典型的用例如逼真的下雨场景。

首先我们要了解,在几何学上圆形可以通过增加等边对称多边形边数来无限逼近。

那么所谓不完美圆形,实际可以通过一个不等边不对称的多边形来实现。

要实现不等边不对称,一个简单的方法是使多边形各个顶点距离中心点的距离(即半径)为一个随机值就好。

为避免半径落差过大,我们可以给其设定一个最大和最小值,然后在这个区间进行随机,代码如下:

function drawCircle(centerX, centerY, minRad, maxRad) {var points = 512; //多边形边的总数目var rad, theta;var twoPi = 2 * Math.PI;var x0, y0;context.strokeStyle = "#aa6699";context.lineWidth = 1.01;context.fillStyle = "#6633aa";context.beginPath();theta = 0;x0 = centerX + rad * Math.cos(theta);y0 = centerY + rad * Math.sin(theta);context.lineTo(x0, y0);for (var i = 0; i < points; i++) {theta += twoPi / points;rad = minRad + Math.random() * (maxRad - minRad); //随机半径x0 = centerX + rad * Math.cos(theta);y0 = centerY + rad * Math.sin(theta);context.lineTo(x0, y0);}context.stroke();context.fill();
}

上面的代码实现效果如下:

上面这样的图形可以用来模拟松果、毛线球、刺猬等物体。

但如果想模拟海岸线、雨滴、云朵等线条比较柔和的物体,则显然不能满足要求。

我们需要边沿有一个平滑的过渡,而分形算法刚好可以用来完成这个任务。

我们假设半径的长度为1,我们来对这个区间进行细分,第1步在线段中间添加一个节点把区间分成2段,随机一个y坐标,第2步在左右半区间内重复类似操作,如此反复,直到达到预先设定的细分粒度。

为了避免线条的起伏过大,我们在给新增中间节点设定y坐标时,使其和所在细分线段的长度正相关,这样随着细分粒度的提高,局部区域的波动就越小,就形成了一个平滑过渡的效果,代码如下:

function setLinePoints(iterations) {var pointList = {};pointList.first = {x: 0,y: 1};var lastPoint = {x: 1,y: 1}var minY = 1;var maxY = 1;var point;var nextPoint;var dx, newX, newY;pointList.first.next = lastPoint;for (var i = 0; i < iterations; i++) {point = pointList.first;while (point.next != null) {nextPoint = point.next;dx = nextPoint.x - point.x;newX = 0.5 * (point.x + nextPoint.x);newY = 0.5 * (point.y + nextPoint.y);newY += dx * (Math.random() * 2 - 1);var newPoint = {x: newX,y: newY};//min, maxif (newY < minY) {minY = newY;} else if (newY > maxY) {maxY = newY;}//put between pointsnewPoint.next = nextPoint;point.next = newPoint;point = nextPoint;}}var normalizeRate = 1 / (maxY - minY);point = pointList.first;while (point != null) {point.y = normalizeRate * (point.y - minY);point = point.next;}return pointList;
}function drawCircle(centerX, centerY, minRad, maxRad, phase) {var point;var rad, theta;var twoPi = 2 * Math.PI;var x0, y0;//生成分形细分顶点链表,用来获取随机半径, 9次迭代将返回512个顶点。var pointList = setLinePoints(9);context.strokeStyle = "#aa6699";context.lineWidth = 1.01;context.fillStyle = "#6633aa";context.beginPath();point = pointList.first;theta = phase;rad = minRad + point.y * (maxRad - minRad);x0 = centerX + rad * Math.cos(theta);y0 = centerY + rad * Math.sin(theta);context.lineTo(x0, y0);while (point.next != null) {point = point.next;theta = twoPi * point.x + phase;rad = minRad + point.y * (maxRad - minRad);x0 = centerX + rad * Math.cos(theta);y0 = centerY + rad * Math.sin(theta);context.lineTo(x0, y0);}context.stroke();context.fill();
}

上面的代码实现效果如下:

我们实现了一个"完美"的不完美的圆形。原文来自踏得网博客。

你可以自己在线试试。

使用Canvas绘制不完美/不规则的圆形相关推荐

  1. android开发 之 Canvas绘制文字,图片

    一.Canvas的常用操作速查表 操作类型 相关API 备注 绘制颜色 drawColor, drawRGB, drawARGB 使用单一颜色填充整个画布 绘制基本形状 drawPoint, draw ...

  2. Canvas绘制圆滑曲线

    canvas 绘制曲线是一个比较容易实现的逻辑,但是对于签名,或者手写板,大屏会议机等设备原生的Canvas.drawPath(); 要求线条曲率完美,直接使用drawPath显然不能满足需求,这方面 ...

  3. canvas绘制多个矩形实现热区图功能

    热区图功能: 在运用后台上传一张背景图,在背景图上框选指定区域,配置对应的跳转链接或领券信息 小程序端判断用户点击位置是否在矩形框选范围内,如果在指定范围内,根据后台配置的功能进行页面跳转或领券. 运 ...

  4. 使用Canvas绘制背景图

    原文  http://www.imququ.com/post/use-canvas-as-background-image.html 最近iCloud Web的Beta版换了UI,整体风格变得和iOS ...

  5. 小程序中使用canvas绘制海报

    最近项目需求使用canvas绘制朋友圈可分享的海报,中间遇到很多问题,于是上网搜索,完美解决后,在此总结一下. 先来看一下效果图,点击按钮生成带二维码的图片. 1.关于canvas画布的宽度和高度 w ...

  6. 小程序canvas绘制自定义分享图片并分享给好友

    小程序的分享有自己的机制,在页面点击右上角,或者页面中的button 采用open-type=share方式也可以触发onShareAppMessage方法. 文档里面明确说明,分享的图片可以采用网络 ...

  7. canvas绘制的文字如何换行

    <html><head><title>canvas绘制的文字如何换行</title><style type="text/css" ...

  8. HTML5 canvas绘制雪花飘落

    Canvas是HTML5新增的组件,它就像一块幕布,可以用JavaScript在上面绘制各种图表.动画等.没有Canvas的年代,绘图只能借助Flash插件实现,页面不得不用JavaScript和Fl ...

  9. canvas绘制时钟

    听了慕课网Sliav Zhou 的课程canvas绘制时钟,记录下来的代码,每句做了注解便于以后学习,原先每次边听别的课边敲码,错误百出,明明原封不动复制的代码,就会出错,还找不到原因,今天可能运气好 ...

最新文章

  1. xampp python linux,Ubuntu的XAMPP着运行python脚本
  2. gin-vue-blog自建博客
  3. frame buffer编程--画点功能和新增字符串代替RGBT
  4. 微信 开发 图片 上传 阿里云 oss 服务器
  5. ajax请求整理(一) 2021.05.12
  6. 中心对称又是轴对称的图形_2020广东省考行测备考:图形推理之对称知多少
  7. java go md5_Go语言中三种不同md5计算方式的性能比较
  8. php mysql_fetch_array 函数大全,深入探讨PHP mysql_fetch_array()函数
  9. 在mysql中字符串的操作_mysql中的字符串操作.doc
  10. nginx 日志正则分割
  11. comsol兼容服务器系统,comsol 云服务器
  12. 非法本法考备考经验总结
  13. Javascript - The same RegExp behave differently
  14. android so 瘦身,Android APK 瘦身实践
  15. 互联网+对酒店IPTV电视系统的影响
  16. [C语言]——矩阵的转置
  17. 计算机基础--作业5,计算机基础第5次作业-第五章-Powerpoint知识题 (精选可编辑)...
  18. 【upload导入、导出】
  19. 阅读nutch.Analysis.jj
  20. shopee售后退款与退货规定

热门文章

  1. 如何才能快速成为一名Java架构师?
  2. PC端网页下载B站视频——you-get(下载所有视频)
  3. keil 更改黑色背景详细步骤,设置代码风格,添加自动格式化插件
  4. vue 页面跳转404_出现404页面怎么办?应该如何处理404页面?
  5. sublime下载gbk编码
  6. PyQT5 (二十五) 绘图API: 绘制不同类型的直线 的案例drawLine()
  7. scp(安全拷贝)和rsync(增量复制)
  8. 大数据之MaxWell
  9. 【免费教程】 SWMM在城市水环境治理中的应用及案例分析
  10. 进程切换之context_switch详解