Вычисление Площади Полигона
Итак, я получил этот код в 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);
результаты кажутся правильными. если вершина прослеживается по часовой стрелке, она будет показывать положительные результаты, но станет отрицательной, если я прослежу вершину в направлении против часовой стрелки. Почему это так?
Как работает этот алгоритм? я действительно хочу знать, какое математическое объяснение стоит за этим, потому что мне все еще трудно поймите объяснение в сети.
4 ответов
представьте, что вы рисуете горизонтальные линии от каждой вершины до оси 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
хотя в приведенном выше примере используется выпуклый многоугольник, это вычисление области корректно для произвольных многоугольников, независимо от того, сколько путей вверх и вниз они могут иметь.
существует алгоритм вычисления площади полигона:
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);
}
за этим нет никакой магии. Просто взгляните на определитель матрицы (http://en.wikipedia.org/wiki/Determinant#2.C2.A0.C3.97.C2.A02_matrices)
edit:
честно говоря: в этом коде есть какая-то магия:
- вам нужна триангуляция. Здесь: мы создаем треугольники, начиная с
(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)
canceles себя. Так что это сложная часть.
он накапливает подписанную область между каждым ориентированным сегментом P[i], P[i+1] и осью Y. В конце цикла область за пределами полигона отменяется (она будет подсчитана дважды с разными знаками), а подписанная область внутри остается.