Як обчислити площу неправильної форми?


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 Це рішення не працюватиме, оскільки вимагає Room, щоб s завжди було повним, і це може бути не так, якщо у мене плеєр побудує Rooms за допомогою Segments. Крім того, функцію закритого приміщення легко визначити (просто проведіть цикл Segmentі переконайтеся, що вони створюють приміщення).

Відповіді:


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
Зауважте, що це можна розширити для обчислення об'єму неправильного 3D-об’єкта, виготовленого з трикутників, і це можна вважати тривіальним випадком основної теореми обчислення.
Дітріх Епп

5
Область тут підписана. Пройдіть через точки в іншому напрямку, і фінал Aзаперечується. Залежно від мети, A = |A|може знадобитися. З негативним кодом області можна знайти область на нерегулярному пончику, використовуючи внутрішній і зовнішній список точок (один у зворотному порядку).
chux

6
Тому що Гаусс або Ейлер, звичайно, мають формулу для цього.
corsiKa

0

Ми також могли використати метод Монте-Карло.

Намалюйте прямокутник навколо довільної форми. Візьміть рівномірно розподілене джерело PRNG, наприклад. mersenne twister, потім зв'язав вихід на прямокутник довжиною X, Y за допомогою функції модуля. Порахуйте ні. випадкових точок, які розташовуються всередині вашої форми. Розділіть на загальну суму отриманих балів. Помножте цей коефіцієнт на площу прямокутника. З кожною ітерацією ви сходитесь до справжньої області. Алгоритм є смішно паралелізованим і може використовуватися для обчислення довільної розмірної форми "обсягів", якщо ви можете визначити, чи координата R ^ N потрапляє в межу форми R ^ N.

.

Тут хтось використовує цей спосіб знайти область кола, а потім використовує це для обчислення pi https://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1: Ви не хочете використовувати модуль, щоб отримати його в діапазоні, ви хочете використовувати рівномірний розподіл або інший розподіл, роблячи це модульним способом, має всілякі статистичні проблеми.
користувач1997744

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, коли вони підійдуть. У всякому разі, це проблема впровадження бібліотеки.
ФранГ

-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.