Вычисление Площади Полигона

Итак, я получил этот код в 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:

честно говоря: в этом коде есть какая-то магия:

  1. вам нужна триангуляция. Здесь: мы создаем треугольники, начиная с (0,0) и наличие (Xi, Yi) и (Xj, Yj)
  2. вы вычисляете определитель для каждого треугольника, чтобы получить: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. В конце цикла область за пределами полигона отменяется (она будет подсчитана дважды с разными знаками), а подписанная область внутри остается.