【问题标题】:How to draw an arbitrary irregular polygon with n sides?如何绘制具有 n 边的任意不规则多边形?
【发布时间】:2019-08-17 01:11:39
【问题描述】:

我正在尝试找到一种算法来绘制一个简单(不允许线相交)的不规则多边形。

边数应由用户定义,n>3

这是一个只绘制复杂多边形(线相交)的初始代码:

var ctx = document.getElementById('drawpolygon').getContext('2d');

var sides = 10;

ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(0, 0);

for(var i=0;i<sides;i++)
{
    var x = getRandomInt(0, 100);
    var y = getRandomInt(0, 100);
    ctx.lineTo(x, y);
}
ctx.closePath();
ctx.fill();

// https://stackoverflow.com/a/1527820/1066234
function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

JSFiddle:https://jsfiddle.net/kai_noack/op2La1jy/6/

我不知道如何确定连接线的下一个点,这样它就不会切断任何其他线。

此外,最后一点必须闭合多边形。

以下是生成的多边形之一的示例:

编辑:今天我认为一种可能的算法是将多边形点规则地排列(例如作为矩形),然后将它们在 xy 方向上重新定位到随机量,同时检查生成的线是否没有被切割。

【问题讨论】:

标签: javascript algorithm polygon


【解决方案1】:

您可以生成随机点,然后将它们与近似的旅行推销员之旅联系起来。任何无法通过2-opt 移动改进的游览都不会有边缘交叉。

【讨论】:

    【解决方案2】:

    我将此solution 移植到 Javascript 1 到 1。代码看起来不是最佳的,但会产生随机凸面(但仍然不规则)多边形。

    //shuffle array in place
    function shuffle(arr) {
        for (let i = arr.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [arr[i], arr[j]] = [arr[j], arr[i]];
        }
        return arr;
    }
    
    /** Based on Sander Verdonschot java implementation **/
    
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y
      }
    }
    
    function generateRandomNumbersArray(len) {
      const result = new Array(len);
      for (let i = 0; i < len; ++i) {
        result[i] = Math.random();
      }
      return result;
    }
    
    function generateRandomConvexPolygon(vertexNumber) {
      const xPool = generateRandomNumbersArray(vertexNumber);
      const yPool = generateRandomNumbersArray(vertexNumber);
    
    //   debugger;
      xPool.sort();
      yPool.sort();
    
      const minX = xPool[0];
      const maxX = xPool[xPool.length - 1];
      const minY = yPool[0];
      const maxY = yPool[yPool.length - 1];
    
      const xVec = []
      const yVec = [];
    
      let lastTop = minX;
      let lastBot = minX;
    
      xPool.forEach(x => {
        if (Math.random() >= 0.5) {
          xVec.push(x - lastTop);
          lastTop = x;
        } else {
          xVec.push(lastBot - x);
          lastBot = x;
        }
      });
    
      xVec.push(maxX - lastTop);
      xVec.push(lastBot - maxX);
    
      let lastLeft = minY;
      let lastRight = minY;
    
      yPool.forEach(y => {
        if (Math.random() >= 0.5) {
          yVec.push(y - lastLeft);
          lastLeft = y;
        } else {
          yVec.push(lastRight - y);
          lastRight = y;
        }
      });
    
      yVec.push(maxY - lastLeft);
      yVec.push(lastRight - maxY);
    
      shuffle(yVec);
      
      vectors = [];
      for (let i = 0; i < vertexNumber; ++i) {
        vectors.push(new Point(xVec[i], yVec[i]));
      }
      
      vectors.sort((v1, v2) => {
        if (Math.atan2(v1.y, v1.x) > Math.atan2(v2.y, v2.x)) {
          return 1;
        } else {
          return -1;
        }
      });
      
      let x = 0, y = 0;
      let minPolygonX = 0;
      let minPolygonY = 0;
      let points = [];
      
      for (let i = 0; i < vertexNumber; ++i) {
        points.push(new Point(x, y));
        x += vectors[i].x;
        y += vectors[i].y;
        
        minPolygonX = Math.min(minPolygonX, x);
        minPolygonY = Math.min(minPolygonY, y);
      }
      
              // Move the polygon to the original min and max coordinates
      let xShift = minX - minPolygonX;
      let yShift = minY - minPolygonY;
    
      for (let i = 0; i < vertexNumber; i++) {
        const p = points[i];
        points[i] = new Point(p.x + xShift, p.y + yShift);
      }
      
      return points;
    }
    
    
    function draw() {
      const vertices = 10;
      const _points = generateRandomConvexPolygon(vertices);
      
      //apply scale
      const points = _points.map(p => new Point(p.x * 300, p.y * 300));
    
      const ctx = document.getElementById('drawpolygon').getContext('2d');
    
    
      ctx.fillStyle = '#f00';
      ctx.beginPath();
      ctx.moveTo(points[0].x, points[0].y);
    
      for(let i = 1; i < vertices ; ++i)
      {
        let x = points[i].x;
        let y = points[i].y;
        ctx.lineTo(x, y);
      }
      ctx.closePath();
      ctx.fill();
    }
    
    draw();
    &lt;canvas id="drawpolygon"&gt;&lt;/canvas&gt;

    【讨论】:

    • 非常感谢!这是凸多边形的解决方案。现在,凹多边形(见我的示例图)的创建只丢失了。我想这就是答案:stackoverflow.com/a/47410079/1066234(在 Python 中)。
    【解决方案3】:

    如果不需要随机,这里有一个快速的不规则n点多边形:

    Points are:
    (0,0)
    ((i mod 2)+1, i) for 0 <= i <= n-2
    
    Lines are between (0,0) and the two extreme points from the second row, as well as points generated by adjacent values of i.
    

    【讨论】:

      猜你喜欢
      • 2018-04-17
      • 2015-09-30
      • 1970-01-01
      • 2014-08-17
      • 2023-03-30
      • 2021-12-05
      • 2021-06-26
      • 2021-07-07
      • 1970-01-01
      相关资源
      最近更新 更多