计算多边形面积

时间:2013-04-29 17:53:02

标签: javascript math

所以我在javascript中得到了这个代码来从网上计算不规则多边形区域。

function polygonArea(X, Y, numPoints)  
{    
area = 0;  // Accumulates area in the loop   
j = numPoints-1;  // The last vertex is the 'previous' one to the first

  for (i=0; i<numPoints; i++)
  { area = area +  (X[j]+X[i]) * (Y[j]-Y[i]); 
      j = i;  //j is previous vertex to i
  }   
  return area/2; 
}

var xPts = [3, 3, 2, 2, 3, 3, 6, 6, 9, 9, 4, 4 ];
var yPts = [2, 4, 4, 5, 5, 6, 6, 5, 5, 3, 3, 2];

var a = polygonArea(xPts, yPts, 4); 
alert("Area  = " + a);

结果似乎是正确的。如果通过顺时针方向跟踪顶点,它将显示正结果,但如果我以逆时针方向跟踪顶点,它将变为负数。为什么会这样?

此算法如何工作?我真的想知道它背后的数学解释是什么,因为我仍然很难理解网上的解释。

5 个答案:

答案 0 :(得分:15)

想象一下从每个顶点到Y轴绘制水平线;对于每个边缘,这将描述一个梯形:

Y-axis
^
|
|--------o (X[j], Y[j])
|         \
|          \
|           \
|------------o (X[i], Y[i])
|
+----------------------------> X-axis

内部循环中的公式(X[j]+X[i]) * (Y[j]-Y[i])计算此梯形的两倍,如果Y[i] <= Y[j],则两倍于Y[i] >= Y[j]的区域。

对于闭合多边形,这自然地从“下行”边缘的区域中减去“上行”边缘左侧的区域。如果多边形是顺时针方向,则可以整齐地切出多边形的精确(加倍)区域;如果是逆时针方向,则会得到负(加倍)区域。

计算给定多边形的面积

Y-axis
^
|
|        o------o
|        |       \
|        |        \
|        o         \
|         \         o                  
|          \       /
|           \     /
|            \   /
|             \ /
|              o
|
+-------------------------> X-axis

采取下行区域:

Y-axis
^
|
|--------o------o
|                \
|                 \
|        o         \
|                   o                  
|                  /
|                 /
|                /
|               /
|--------------o
|
+-------------------------> X-axis

减去上行区域:

Y-axis
^
|
|--------o      o
|        |
|        |
|        o
|         \         o                  
|          \
|           \
|            \
|             \
|--------------o
|
+-------------------------> X-axis

虽然上面的例子使用凸多边形,但这个面积计算对于任意多边形都是正确的,无论它们有多少上行和下行路径。

答案 1 :(得分:7)

There is an algorithm to calculate polygon area:

function calcPolygonArea(vertices) {
    var total = 0;

    for (var i = 0, l = vertices.length; i < l; i++) {
      var addX = vertices[i].x;
      var addY = vertices[i == vertices.length - 1 ? 0 : i + 1].y;
      var subX = vertices[i == vertices.length - 1 ? 0 : i + 1].x;
      var subY = vertices[i].y;

      total += (addX * addY * 0.5);
      total -= (subX * subY * 0.5);
    }

    return Math.abs(total);
}

答案 2 :(得分:1)

背后没有魔法。只需看看矩阵的行列式(http://en.wikipedia.org/wiki/Determinant#2.C2.A0.C3.97.C2.A02_matrices

编辑:

老实说:这段代码中有一些魔力:

  1. 你需要任何三角测量。在这里:我们创建从(0,0)开始并拥有(Xi, Yi)(Xj, Yj)
  2. 的三角形
  3. 您计算每个三角形的行列式:Xi Yj - Xj Yi。但是这里有人计算(X[j]+X[i]) * (Y[j]-Y[i]) = Xj Yj - Xj Yi + Xi Yj - Xi Yi = (Xj Yj - Xi Yi) + (Xi Yj - Xj Yi)。但幸运的是,如果你添加所有那些部分(Xj Yj - Xi Yi)自我消除。所以这是棘手的部分。

答案 3 :(得分:1)

这是一个使用 Andrii Verbytskyi's response 的片段:

/* Get area of a polygon/surface */
function area(polygon) {
    let total = 0;
    for (let i = 0; i < polygon.length; i++) {
        const addX = polygon[i][0];
        const addY = polygon[i === polygon.length - 1 ? 0 : i + 1][1];
        const subX = polygon[i === polygon.length - 1 ? 0 : i + 1][0];
        const subY = polygon[i][1];
        total += (addX * addY * 0.5) - (subX * subY * 0.5);
    }
    return Math.abs(total);
}

function drawPolygon(context, polygon, strokeStyle, fillStyle) {
  context.strokeStyle = strokeStyle;
  context.fillStyle = fillStyle;
  context.beginPath();
  context.moveTo(polygon[0][0], polygon[0][1]); //first vertex
  for (var i = 1; i < polygon.length; i++)
    context.lineTo(polygon[i][0], polygon[i][1]);
  context.lineTo(polygon[0][0], polygon[0][1]); //back to start
  context.fill();
  context.stroke();
  context.closePath();
}

display = function(n) {
  var context = document.getElementById("canvas").getContext("2d");
  context.clearRect(0, 0, 500, 500);
  drawPolygon(context, polygons[n], "#888", "#88f");
  document.querySelector('span').textContent = area(polygons[n]);
};

const polygons = [
    [[100, 100], [100, 300], [300, 400], [400, 250], [300, 0]],
    [[300, 300], [300, 100], [0, 0], [-100, 400]],
    [[50, 150], [200, 50], [350, 150], [350, 250], [250, 320], [200, 250], [150, 350], [100, 250]],
    [[100, 100], [300, 100], [400, 300], [100, 300]]
];

const buttons = document.querySelectorAll("button");
for (let counter = 0; counter < buttons.length; counter++) {
    buttons[counter].addEventListener("click", function(){
      window.onload = display(counter);
   });
}
window.onload = display(0);
<button onclick="display(0)">Polygon 0</button>
<button onclick="display(1)">Polygon 1</button>
<button onclick="display(2)">Polygon 2</button>
<button onclick="display(3)">Polygon 3</button>
Polygon area : <span id='area'></span>
<canvas id='canvas' width='400' height='400'></canvas>

答案 4 :(得分:0)

它累积每个定向区段P [i],P [i + 1]和Y轴之间的有符号区域。在循环结束时,多边形外部的区域取消(将使用不同的符号计算两次),并且内部的签名区域仍然存在。