canvas里边怎样根据任意点绘图1个多边形的方式

日期:2021-02-23 类型:科技新闻 

关键词:html网页制作,php网页制作,网页设计稿,网页编辑工具,学生网页设计模板

诱因

今日在学习培训《HTML5+Javascript动漫基本》这本书的情况下,在第8章的第3节讲到怎样用3个弹黄联接3个点来做拉伸健身运动。

在做完事例以后,就想起假如是4个点,5个点,如何。

就改变了1下编码,把点的数目自变量化。最后的实际效果是能完成各个点最后的拉伸健身运动到均衡,但是点之间的连线并不是很漂亮,一些是交叉式的。

因而就想着能不可以提升这1块。

转动连线

前面事例里边的点,全是任意部位,因此连线不能控。因此想先从这块下手。

先以某1个点为参考点,得到别的点相对这个点的角度。

随后依照角度从小到大的去联接这些点,这样就可以画出1个一切正常的多边形了。

大概完成编码以下:

let balls = [];
let ballNum = 6;
let firstBall = null;
while(ballNum--) {
  let ball = new Ball(20, parseColor(Math.random() * 0xffffff))
  ball.x = Math.random() * width;
  ball.y = Math.random() * height;
  balls.push(ball)

  if (!firstBall) {
    firstBall = ball
    ball.angle = 0
  } else {
    const dx = ball.x - firstBall.x,
          dy = ball.y - firstBall.y;

    ball.angle = Math.atan2(dy, dx);
  }
}

// 尝试让球连线是1个正多边形
balls = balls.sort((ballA, ballB) => {
  return ballA.angle - ballB.angle
})

这样在最终绘图连线的情况下,遍历数字能量数组就可以依照角度从小到大来绘图了。

实际效果以下:

这样是能巨大的降低交叉式线的状况,可還是没法彻底防止。

接下来,想尝试提升这个计划方案,例如angle用Math.abs来取正,或每个点都找夹角最少的点来连线。但是結果都不好,没法防止交叉式线。

根据管理中心点转动

后边又想起1个思路,假如能明确多边形的管理中心点,那末各自测算全部点相对管理中心点的夹角,就可以以顺时针或逆时针来联接这些点。

但是在网络上找了半天,全部点优化算法里边,全是规定有1系列按某个时针次序排序的点。

但是假如我有这些点,就早已能绘图多边形了。只好舍弃

X轴两方面点切分

无可奈何之下只好找Google,随后就发现了知乎上的1个回答挺好的: 怎样将平面上无序的1组点连成1个简易多边形?

实际优化算法叙述,大伙儿看那个回答就好,我就不赘述了。

但是在联接上链和下链的情况下,实际上要是确保上链是X轴降序联接,下链是X轴升序联接便可(以逆时针方位绘图)。至于X轴同样的点,无论是优先选择Y轴大的還是小的都可以以。

完成的情况下,是严苛依照回答里边的优化算法完成的。

在分辨1个点是属于上链還是下链的情况下,1刚开始想的是根据两点明确平行线的涵数方程,再引进点的座标来测算。但是后边想起,全部的点都以最左侧的顶点来测算斜角,随后依据角度尺寸来区划,视觉效果上更好了解。

大概编码以下:

let balls = [];
let tempBalls = [];
let ballNum = 6;
let isDragingBall = false;

while(ballNum--) {
  let ball = new Ball(10, parseColor(Math.random() * 0xffffff))
  ball.x = Math.random() * width;
  ball.y = Math.random() * height;
  tempBalls.push(ball)
}

// 让点按X轴升序排列
tempBalls = tempBalls.sort((ballA, ballB) => {
  return ballA.x - ballB.x
})

// 找X轴上下顶点
let firstBall = tempBalls[0],
    lastBall = tempBalls[tempBalls.length ⑴];
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 false
  }
  let angle = Math.atan2(ball.y - firstBall.y, ball.x - firstBall.x);
  if (angle > splitLineAngle) {
    lowerBalls.push(ball)
  } else {
    upperBalls.push(ball)
  }
})

// 解决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) => {
  if (ballA.x !== ballB.x) {
    return ballB.x - ballA.x
  }
  return ballB.y - ballB.x
})

// 逆时针联接全部的点
balls = [firstBall].concat(lowerBalls, [lastBall], upperBalls)

balls = balls.map((ball, i) => {
  ball.text = i + 1;
  return ball
})

最后回到的balls,便是按逆时针排列的多边形的点了。

实际效果以下:

各个球的內部情况以下:

 

以上便是本文的所有內容,期待对大伙儿的学习培训有一定的协助,也期待大伙儿多多适用脚本制作之家。

上一篇:canvas探照灯实际效果的示例编码 返回下一篇:没有了