这篇文章主要介绍画布里面怎么基于随机点绘制一个多边形,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
<强>起因强>
今天在学习《HTML5 + Javascript动画基础》这本书的时候,在第八章的第三节讲到如何用三个弹簧连接三个点来做拉伸运动。
在做完例子之后,就想到如果是四个点,五个点,怎么样。
就改写了一下代码,把点的数目变量化。最终的效果是能实现各个点最终的拉伸运动到平衡,可是点之间的连线不是很好看,有些是交叉的。
于是就想着能不能优化这一块。
<>强旋转连线强>
前面例子里面的点,都是随机位置,所以连线不可控。所以想先从这块着手。
先以某一个点为参照点,获得其他点相对于这个点的角度。
然后按照角度从小到大的去连接这些点,这样就能画出一个正常的多边形了。
大致实现代码如下:
let balls =, []; let ballNum =, 6; let firstBall =,空; 而(ballNum——), { let 才能;ball =, new 球(20日,parseColor (math . random (), *, 0 xffffff)) ball.x 才能=,math . random(), *,宽度; ball.y 才能=,math . random(), *,高度; balls.push才能(球) if 才能;(! firstBall), { ,,,firstBall =球 ,,,ball.angle =0 ,,},{else ,,,const dx =, ball.x 作用;firstBall.x, ,,,,,,,,,dy =, ball.y 作用;firstBall.y; ,,,ball.angle =, Math.atan2 (dy, dx); ,,} }//,尝试让球连线是一个正多边形 时间=balls balls.sort ((ballA, ballB),=祝辞,{ return 才能;ballA.angle 安康;ballB.angle })
这样在最后绘制连线的时候,遍历数组就能按照角度从小到大来绘制了。
效果如下:
这样是能极大的减少交叉线的情况,可还是无法完全避免。
接下来,想尝试优化这个方案,比如角度用数学。abs来取正,或者每一个点都找夹角最小的点来连线。可是结果都不行,无法避免交叉线。
<>强基于中心点旋转强>
后面又想到一个思路,如果能确定多边形的中心点,那么分别计算所有点相对于中心点的夹角,就能以顺时针或者逆时针来连接这些点。
可是在网上找了半天,所有点算法里面,都是要求有一系列按某个时针顺序排列的点。
可是如果我有这些点,就已经能绘制多边形了。只好放弃
<强> X轴两极点分割强>
无奈之下只好找谷歌,然后就发现了知乎上的一个答案挺好的:如何将平面上无序的一组点连成一个简单多边形?
具体算法描述,大家看那个答案就好,我就不赘述了。
不过在连接上链和下链的时候,其实只要保证上链是X轴降序连接,下链是X轴升序连接即可(以逆时针方向绘制)。至于X轴相同的点,不管是优先Y轴大的还是小的都可以。
实现的时候,是严格按照答案里面的算法实现的。
在判断一个点是属于上链还是下链的时候,一开始想的是基于两点确定直线的函数方程,再引入点的坐标来计算。不过后面想的到,所有的点都以最左边的极点来计算斜角,然后根据角度大小来划分,视觉上更好理解。
大致代码如下:
let balls =, []; let tempBalls =, []; let ballNum =, 6; let isDragingBall =,假; 而(ballNum——), { let 才能;ball =, new 球(10,parseColor (math . random (), *, 0 xffffff)) ball.x 才能=,math . random(), *,宽度; ball.y 才能=,math . random(), *,高度; tempBalls.push才能(球) }//,让点按X轴升序排序 时间=tempBalls tempBalls.sort ((ballA, ballB),=祝辞,{ return 才能;ballA.x 安康;ballB.x })//,找X轴左右极点 let firstBall =, tempBalls [0], ,,,lastBall =, tempBalls [tempBalls.length 1]; let smallXBalls =, tempBalls.filter (ball =祝辞,ball.x ===, firstBall.x), ,,,bigXBalls =, tempBalls.filter (ball =祝辞,ball.x ===, lastBall.x)//,处理左右极点有多个的情况 if (smallXBalls.length 祝辞,1),{ smallXBalls.sort才能((ballA, ballB),=祝辞,{ ,,,return ballB.y 作用;ballA.y })才能 } if (bigXBalls.length 祝辞,1),{ bigXBalls.sort才能((ballA, ballB),=祝辞,{ ,,,return ballB.y 作用;ballA.y })才能 } 时间=firstBall smallXBalls [0] 时间=lastBall bigXBalls [0]//,获得极点连线的角度 let splitLineAngle =, Math.atan2 (lastBall.y 安康;firstBall.y, lastBall.x 作用;firstBall.x); let upperBalls =, [], ,,,lowerBalls =, [];//,所有其他点跟firstBall计算角度//,大于splitLineAngle的都是下链//,其他是上链 tempBalls.forEach (ball =祝辞,{ if 才能;(ball ===, firstBall | |, ball ===, lastBall), { ,,,return 错误的 ,,} let 才能;angle =, Math.atan2 (ball.y 安康;firstBall.y, ball.x 作用;firstBall.x); if 才能;(angle 祝辞,splitLineAngle), { ,,,lowerBalls.push(球) ,,},{else ,,,upperBalls.push(球) ,,} })//,处理X轴相同情况的排序 时间=lowerBalls lowerBalls.sort ((ballA, ballB),=祝辞,{ if 才能;(ballA.x !==, ballB.x), { ,,,return ballA.x 作用;ballB.x ,,} return 才能;ballB.y 安康;ballA.y }) 时间=upperBalls upperBalls.sort ((ballA, ballB),=祝辞,{ null null null null null null null null null null null null null画布里面怎么基于随机点绘制一个多边形