从点创建多边形的算法

Jos*_*ski 3 javascript algorithm geometry

我想找到一种从随机点创建多边形的好方法。

所有的点都应该用在多边形中,所以每个点都有两个由两条边连接的邻居。任何边缘都不应该与另一个边缘交叉。

以下是可接受结果的示例:

在此处输入图片说明

这里是什么将一个例子被接受,因为有彼此交叉的边缘:

在此处输入图片说明

有这个算法吗?

tri*_*cot 13

你可以:

  1. 确定一些好的开始点,而不是给定的点之一。使用一些启发式方法。例如,给定点的“质心”可能是一个有用的选择。但是在凸包内选择任何一个点都会产生一个不相交边的多边形。根据选择,多边形可能更“平滑”或“平滑”。

  2. 将给定点的坐标转换为极坐标,其中第一步中选择的点是原点 (0, 0)。

  3. 按极坐标对点进行排序:首先按极角,然后按半径(或实际上是使用平方根函数省略的半径的平方)。

  4. 使用此顺序绘制多边形。

这是交互式代码段中的实现:

function squaredPolar(point, centre) {
    return [
        Math.atan2(point[1]-centre[1], point[0]-centre[0]),
        (point[0]-centre[0])**2 + (point[1]-centre[1])**2 // Square of distance
    ];
}

// Main algorithm:
function polySort(points) {
    // Get "centre of mass"
    let centre = [points.reduce((sum, p) => sum + p[0], 0) / points.length,
                  points.reduce((sum, p) => sum + p[1], 0) / points.length];

    // Sort by polar angle and distance, centered at this centre of mass.
    for (let point of points) point.push(...squaredPolar(point, centre));
    points.sort((a,b) => a[2] - b[2] || a[3] - b[3]);
    // Throw away the temporary polar coordinates
    for (let point of points) point.length -= 2; 
}

let points = [];

// I/O management

let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");

function draw(points) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if (!points.length) return;
    for (let [x, y] of points) {
        ctx.beginPath();
        ctx.arc(x, y, 3, 0, 2 * Math.PI, true);
        ctx.fill();
    }
    ctx.beginPath();
    ctx.moveTo(...points[0]);
    for (let [x, y] of points.slice(1)) ctx.lineTo(x, y);
    ctx.closePath();
    ctx.stroke();
}

canvas.onclick = function (e) {
    let x = e.clientX - this.offsetLeft;
    let y = e.clientY - this.offsetTop;
    let match = points.findIndex(([x0, y0]) => Math.abs(x0-x) + Math.abs(y0-y) <= 6);
    if (match < 0) points.push([x, y]);
    else points.splice(match, 1); // delete point when user clicks near it.
    polySort(points);
    draw(points);
};
Run Code Online (Sandbox Code Playgroud)
canvas { border: 1px solid }
Run Code Online (Sandbox Code Playgroud)
Click to draw points. Polygon will be drawn in real-time:<br>
<canvas></canvas>
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常酷的算法!我喜欢它使用极坐标来模仿人类从一点开始然后顺时针/逆时针移动的直觉。如果我想进一步了解这个算法,这个算法叫什么?:-) (2认同)