所以我在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);
结果似乎是正确的。如果通过顺时针方向跟踪顶点,它将显示正结果,但如果我以逆时针方向跟踪顶点,它将变为负数。为什么会这样?
此算法如何工作?我真的想知道它背后的数学解释是什么,因为我仍然很难理解网上的解释。
答案 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)
编辑:
老实说:这段代码中有一些魔力:
(0,0)
开始并拥有(Xi, Yi)
和(Xj, Yj)
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轴之间的有符号区域。在循环结束时,多边形外部的区域取消(将使用不同的符号计算两次),并且内部的签名区域仍然存在。