canvas 凸包效果

前言

微信公众号:前端不只是切图

代码运行的最终效果在文章最后

什么是凸包

本篇文章主要阐述如何在canvas上实现凸包的效果,我们先来看看下什么是凸包,先上附图

从上面的图可以看出,图中的内容包含点p0-点p12,而红框部分就是凸包,可以看出其由最外围的点连接构成刚好把所有的内容都包住,就像橡皮筋勒紧的效果,当运用到canvas上时,点相当于canvas上的像素

Andrew算法

本文主要使用Andrew算法实现凸包的效果,先上个gif图,看下这个算法的全貌

可能刚开始看有点懵逼,没事,其实算法思路并不复杂,继续往下看,以下是随便勾勒的canvas,其内容像是一个五角星

由于我们需要操作像素点,可以通过ctx.getImageData()拿到整个canvas的所有像素点,再做逐一分析,首先,我们要找到一个起始点,即最小的x坐标,这个点一定是在凸包上的

可以通过上到下然后从左到右遍历canvasimageData,当遇到第一个alpha通道不为0的像素,就是我们要找的起始点,然后我们将它的坐标入栈,继续遍历,找下一个点

如图所示,我们往右行进一步,其实就是x坐标 +1(现实中像素点是很小的,图中为了方便理解就点的比较大 ),我们从下往上遍历当前x坐标下y轴上的每个点,就是上图中红线的部分,找到第一个alpha通道不为0的像素,我们把这个像素的坐标入栈,现在我们栈的长度是2,我们以此方法继续行进

如上图,由于没有特殊情况,到这里我们可以一直把点入栈,那什么是特殊情况呢,我们继续往右行进,把图片放大一些方便理解

当前我们的栈顶是p2,其前一个元素是p1,将p1 -> p2作为一个向量我们记作prev,下一个点是p3,再将p2 -> p3作为一个向量我们记作nextAndrew算法的核心是,当next向量在prev向量的左侧,我们可以把点p3直接入栈,如果next向量在prev向量的右侧,那栈顶元素(p2)出栈,然后继续以当前栈顶前一个元素(p1的上一个元素)和栈顶元素(p1)组成向量prev,栈顶元素(p1)和p3组成向量next,进行方向比较,如果向量next还是在向量prev的右侧就继续把栈顶元素出栈,继续往前比较,直到比较到是左侧,才将p3入栈,然后才继续向右行进

向量通过终点坐标 - 起始坐标 得到

javascript 复制代码
function create(v1, v2) {
    return {
        x: v2.x - v1.x,
        y: v2.y - v1.y
    };
}

向量方向通过叉乘得到,结果大于0就是右侧

javascript 复制代码
function cross(v1, v2) {
    return v1.x * v2.y - v2.x * v1.y;
}

然后我们按照以上的规则,继续向右进行

由于我们一开始是从下到上,从左到右遍历,所以最终我们得到是4个点形成的一个下凸包区域

之后我们只需要再从上到下,从右到左,将会得到一个上凸包的区域,合并两个凸包数组就是我们要的的凸包

最终效果

以上的图都是纯手画的,有点手残,我们看下最终代码的效果

这里在canvas上把计算后凸包的各个点做了ctx.moveTo()连接,并通过ctx.fill()的形式绘制,同时增加了描边的宽度,整体看起来会好看些。

相关推荐
codeGoogle4 小时前
自研 IM 还是选择第三方 SDK?企业开发者应该如何权衡?
前端·后端·程序员
用户938515635075 小时前
React Context 与自定义 Hook 从底层到实践:「跨层级通信 + 副作用封装」全解析
前端·javascript·react.js
滴滴答答哒6 小时前
VUE3+element-plus MultiSelect 多选下拉组件
前端·javascript·vue.js
其美杰布-富贵-李6 小时前
04 watch 与 Vue 响应式数据流
前端·javascript·vue.js
赵大仁7 小时前
生成式 UI 实战:用 JSON Schema + React 动态渲染 AI 界面
前端·ai·react·next.js·前端架构·生成式ui
kyriewen8 小时前
我排查了一个React内存泄漏——罪魁祸首是这3个被忽略的清理函数
前端·javascript·面试
IT_陈寒9 小时前
我又被JavaScript的隐式类型转换坑了
前端·人工智能·后端
其美杰布-富贵-李9 小时前
03 ref、reactive 与 computed 响应式数据
前端·javascript·vue.js
OpenTiny社区9 小时前
GenUI SDK v1.3.0 发布|多框架兼容,一键换物料,渲染器 & 演练场全面增强!
前端·ai编程
用户938515635079 小时前
useRef + Web Worker 实战:React 如何优雅地拥抱多线程
前端·javascript·react.js