Как рассчитать площадь неправильной формы?


17

У меня есть объект комнаты, определенный набором циклических отрезков, для которого мне нужно вычислить площадь. Классы могут быть описаны следующим образом (в псевдокоде):

class Point {
    float x; 
    float y;
    ...
    float distanceFrom(Point p);
}

class Segment {
    Point start;
    Point end;
    ...
    float length();
}

class Room {
    List<Segment> walls;
    ...
    float area();
}

Стены комнаты никогда не могут пересекаться нигде, кроме как в конечных точках сегментов, и любые созданные «подциклы» также будут разделены на новую комнату. Решение не обязательно должно быть идеально точным (допустимая погрешность 10%) и также не очень часто (<1 / с).


7
Было бы более целесообразно Roomсодержать список Points, а затем получить сегменты, соединив каждую точку вместе, а затем вернув ее обратно. В противном случае, с вашей текущей настройкой, это очень восточно, чтобы получить неправильные значения (например, незакрытая комната, комната со стеной посередине и т. Д.). Это был бы лучший вариант.
— MCMastery

Другой вариант - верхняя триангуляция формы и вычисление площадей каждого треугольника. Трудной частью является триангуляция. Выполнимо, но не всегда красиво. Ответ от шнурка еще лучше.
— Draco18s больше не доверяет SE

@MCMastery Это решение не будет работать, так как оно требует, чтобы Rooms всегда было завершено, и это может быть не так, если у меня есть игрок, который собирает Rooms, используя Segments. Кроме того, функцию закрытой комнаты легко определить (просто переберите Segments и убедитесь, что они создают комнату).

Ответы:


31

Вы можете использовать формулу шнурка Гаусса :

Вам нужно взять координату x каждой точки, умножить их на координату y следующей точки, затем вычесть координату y текущей точки, умноженную на координату x следующей точки, из результата и добавить их к общей площади. После того, как вы сделали это для каждой точки, разделите пополам общую площадь, чтобы получить фактическую площадь многоугольника. Если текущая точка является последней, то следующая является первой.

A = 0

for (i = 0; i < points.length; i++) do

    A += points[i].x * points[(i + 1) % points.length].y - points[i].y * points[(i + 1) % points.length].x

end

A /= 2

2
Я всегда использовал это, чтобы вычислить перекрестное произведение двух векторов, никогда не знал, что это было названо алгоритмом
— Сидар

3
Обратите внимание, что это можно расширить, чтобы вычислить объем нерегулярного трехмерного объекта из треугольников, и это можно считать тривиальным случаем основной теоремы исчисления.
— Дитрих Эпп

5
Площадь здесь подписана. Пройдите точки в другом направлении, и финал Aотменяется. В зависимости от цели, A = |A|может понадобиться. С помощью отрицательного кода области можно найти область на неправильном пончике, используя внутренний и внешний список точек (один в обратном порядке).
— chux - Восстановить Монику

6
Потому что, конечно, у Гаусса или Эйлера есть формула для этого.
— CorsiKa

0

Мы также могли бы использовать метод Монте-Карло.

Нарисуйте прямоугольник вокруг произвольной формы. Возьмите равномерно распределенный источник PRNG, например. Mersenne Twister, а затем ограничить выход по X, Y длины прямоугольника, используя функцию по модулю. Считайте нет. случайных точек, которые приземляются внутри вашей фигуры. Разделите на общее количество полученных баллов. Умножьте это отношение на площадь прямоугольника. С каждой итерацией вы будете сходиться к истинной области. Алгоритм смехотворно распараллеливается и может использоваться для вычисления произвольных размерных «объемов» фигуры, при условии, что вы можете определить, находится ли координата R ^ N в пределах границы R ^ N фигуры.

,

Здесь кто-то использует этот метод, чтобы найти область круга, а затем использует его для вычисления числа пи https://www.youtube.com/watch?v=VJTFfIqO4TU.


2
-1: Вы не хотите использовать модуль по модулю, чтобы получить его в диапазоне, вы хотите использовать равномерное распределение или другое распределение, делая это по модулю, имеет все виды статистических проблем.
— user1997744

12
Этот метод может быть полезен, когда у нас нет простого многоугольника, а есть некая неявная форма, границу которой трудно выразить, например, фрактальный шарик или метабол. Однако в случае многоугольника, как в вопросе, кажется, что это будет излишне дорого.
— DMGregory

Как указал @DMGregory, это не то, что я искал. Тем не менее, я думаю, что это заслуживает +1, если кому-то еще это нужно.

Это интересно, но не станет ли стоимость тестов на включение слишком высокой? То есть, если у вас есть форма, которая достаточно сложна, чтобы оправдать такой подход, разве тесты на включение не будут действительно дорогими, поэтому вы не захотите делать их тоннами? (в предположении многоугольников)
— Маттиа

Хорошо, по модулю действительно проблематично, но это простое решение. Что мы действительно получаем, так это случайные P = 1/2 биты 0/1, поэтому мы получаем равномерное распределение чисел, например. для 3 битов от 0 до 7. Выполнение rand% 5, если случайное число принимает значение 6 или 7, преобразуется в 1 или 2, эффективно увеличивая 1,2, делая распределение неравномерным. Чтобы избежать этого, вам нужно что-то вроде конечного автомата, который вращает отображение, например. 6,7 карты до 1,2, затем до 3,4, затем 5,0, и это продолжается. Мы также могли бы выбросить 6,7, когда они подошли. Во всяком случае, это проблема реализации библиотеки.
— FranG

-1

Другой подход: не надо.

Вместо:

while (Segments.Count > 3)
{
    Segment A = Segments[Segments.Count - 2];
    Segment B = Segments[Segments.Count - 1];
    Segment C = new Segment(B.End, A.Start);
    Triangle T = new Triangle(A, B, C);
    Segments[Segments.Count - 2] = C;
    Segments.RemoveAt(Segments.Count - 1);
    if (B is inside the new shape Segments)
        Area -= T.Area;
    else
        Area += T.Area;
}
Area += new Triangle(Segments[0], Segments[1], Segments[2]).Area;

В основном, отрежьте треугольник. Площадь треугольника проста, и при этом мы сократили количество сегментов остатка на единицу. Повторяйте до тех пор, пока не останется треугольник.


2
Формула Гаусса «Шнурки» - это сокращение, которое вдвое сокращает количество вычислений. Проработай это.
— Питер Гиркенс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.