如果我有一个点列表,[(x1,y1), (x2,y2), (x3,y3)...]
,有什么办法可以使它们按顺时针方向排列?
顺时针方向是指相对于形状中心的顺时针方向。
最佳答案
首先,您必须找到由点定义的形状的中心,因为将相对于该点定义旋转。
然后,您必须计算这些点相对于中心和x
轴的角度。
要计算角度,可以使用Math.atan2(y - center.y, x - center.x)
。
然后使用Array.sort
按角度对点进行排序。
一旦正确地排列了点,您应该能够画出一条连接点且不相交的线。我使用画布进行了演示。起点以正方形显示。我已将x/y
轴绘制为转换为您的点的质心。我还添加了将点连接到质心的线,以实现其角度。
const width = 250;
const height = 250;
// Random points
const points = Array.from({ length: 20 }, () =>
({ x: Math.random() * width, y: Math.random() * height })
);
// Get the center (mean value) using reduce
const center = points.reduce((acc, { x, y }) => {
acc.x += x / points.length;
acc.y += y / points.length;
return acc;
}, { x: 0, y: 0 });
// Add an angle property to each point using tan(angle) = y/x
const angles = points.map(({ x, y }) => {
return { x, y, angle: Math.atan2(y - center.y, x - center.x) * 180 / Math.PI };
});
// Sort your points by angle
const pointsSorted = angles.sort((a, b) => a.angle - b.angle);
// Draw them
const canvas = document.querySelector('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
let lastPoint = pointsSorted[0];
ctx.fillRect(lastPoint.x, lastPoint.y, 5, 5);
ctx.beginPath();
ctx.moveTo(0, center.y);
ctx.lineTo(width, center.y);
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(center.x, 0);
ctx.lineTo(center.x, height);
ctx.strokeStyle = 'black';
ctx.stroke();
pointsSorted.forEach(({ x, y }) => {
ctx.beginPath();
ctx.moveTo(lastPoint.x, lastPoint.y);
ctx.lineTo(x, y);
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.fillRect(x, y, 2, 2);
ctx.beginPath();
ctx.moveTo(center.x, center.y);
ctx.lineTo(x, y);
ctx.strokeStyle = 'grey';
ctx.stroke();
lastPoint = { x, y };
});
canvas {
border: 1px solid black;
}
<canvas></canvas>
希望有帮助!