Düzensiz bir şeklin alanı nasıl hesaplanır?


17

Alan hesaplamak için gereken döngü çizgi parçalarının bir koleksiyon tarafından tanımlanan bir oda nesnesi var. Sınıflar aşağıdaki şekilde (sözde kodda) tanımlanabilir:

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();
}

Bir odanın duvarları asla hiçbir yerde kesişemez, ancak segmentlerin uç noktalarında ve oluşturulan "alt döngüler" de yeni bir odaya ayrılacaktır. Çözeltinin mükemmel bir şekilde doğru olması gerekmez (% 10 hata payı kabul edilebilir) ve aynı zamanda çok sık hesaplanmaz (<1 / s).


7
Bir s Roomlistesi içermesi Pointve daha sonra her bir noktayı birbirine bağlayıp daha sonra tekrar döngüye sokması daha anlamlı olacaktır . Aksi takdirde, mevcut kurulumunuzla yanlış değerler elde etmek çok doğudur (örn. Kapatılmamış oda, ortada duvarlı oda vb.). Bu en iyi seçenek olacaktır.
MCMastery

Başka bir seçenek şekli üst üçgenlemek ve her üçgenin alanlarını hesaplamaktır. Zor kısmı nirengi. Yapılabilir, ancak her zaman hoş değil. Ayakkabı bağı yanıtı hala çok daha iyi.
Draco18s artık SE

@MCMastery Bu çözüm işe yaramıyor, çünkü Roomher zaman s'nin eksiksiz olmasını gerektiriyor ve eğer oyuncu Rooms kullanarak Segments oluşturuyorsa, durum böyle olmayabilir . Ayrıca, kapalı oda işlevini tanımlamak kolaydır (sadece Segments boyunca döngü yapın ve bir oda oluşturduklarından emin olun).

Yanıtlar:


31

Gauss'un ayakkabı bağı formülünü kullanabilirsiniz :

Her noktanın x koordinatını almanız, bunları bir sonraki noktanın y koordinatıyla çarpmanız ve ardından geçerli noktanın y koordinatını bir sonraki noktanın x koordinatıyla çarpmanız ve sonuçtan toplam alana eklemeniz gerekir. Bunu her nokta için yaptıktan sonra, çokgenin gerçek alanını elde etmek için toplam alanı yarıya indirin. Geçerli nokta sonuncuysa, sonraki nokta ilk olur.

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
Her zaman iki vektörün çapraz ürününü hesaplamak için ona ayakkabı bağı algoritması denildiğini hiç bilmezdim
Sidar

3
Bunun, üçgenlerden oluşan düzensiz bir 3D nesnenin hacmini hesaplamak için genişletilebileceğini ve hesabın temel teoreminin önemsiz bir durumu olarak düşünülebileceğini unutmayın.
Dietrich Epp

5
Buradaki alan imzalandı. Diğer yöndeki noktalardan Ageçin ve final reddedilir. Hedefe bağlı olarak a A = |A|gerekebilir. Negatif alan kodu ile iç ve dış nokta listesini (ters sırada bir) kullanarak düzensiz bir donut alanı bulabilirsiniz.
chux - Monica'yı eski haline getir

6
Tabii ki Gauss ya da Euler'in bir formülü var.
corsiKa

0

Monte Carlo yöntemini de kullanabiliriz.

Rasgele şeklin etrafına bir dikdörtgen çizin. Düzgün dağılmış bir PRNG kaynağı alın. mersenne twister, sonra modulo fonksiyonunu kullanarak çıktıyı dikdörtgenin X, Y uzunluklarına bağladı. Hayır. şeklinize giren rastgele noktaların. Oluşturulan toplam nokta miktarına bölün. Bu bölümü dikdörtgenin alanı ile çarpın. Her bir yineleme ile gerçek alana yakınlaşacaksınız. Algoritma gülünç derecede paralel hale getirilebilir ve bir R ^ N koordinatının şeklin R ^ N sınırına girip girmediğini belirleyebildiğiniz sürece, rastgele boyutlu şekil 'hacimlerini' hesaplamak için kullanılabilir.

.

Burada birisi bu yöntemi bulmak daire alanı kullanıyor sonra pi hesaplamak için kullanır https://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1: Menzil elde etmek için modulo kullanmak istemiyorsunuz, tekdüze bir dağılım veya başka bir dağıtım kullanmak istiyorsunuz, modulo yolunun her türlü istatistiksel sorunu var.
user1997744

12
Bu yöntem, basit bir çokgene sahip olmadığımızda değil, fraktal veya metaball blob gibi, sınırını ifade etmek zor olan bir tür örtülü şekle sahip olduğunda faydalı olabilir. Yine de sorudaki gibi bir çokgen söz konusu olduğunda, gereksiz derecede pahalı gibi görünüyor.
DMGregory

@DMGregory'nin işaret ettiği gibi, aradığım şey bu değildi. Ancak, bir başkasının ihtiyacı olması durumunda +1 değerini hak ettiğini düşünüyorum.

Bu ilginç ama dahil etme testlerinin maliyeti yasaklanmıyor mu? Yani, bu yaklaşımı garanti etmek için yeterince karmaşık bir şekle sahipseniz, dahil etme testleri de pahalı olmaz, bu yüzden tonlarca yapmak istemez miydiniz? (çokgenler varsayalım)
Mattia

Tamam modulo gerçekten sorunlu ama basit bir çözüm. Gerçekte elde ettiğimiz şey rastgele P = 1/2 bit 0/1'dir, bu yüzden elde ettiğimiz sayıların düzgün bir dağılımıdır. Rand% 5'in yapılması, rastgele bir sayı 6 veya 7 değerini alırsa, 1 veya 2'ye eşlenir ve 1,2 frekansı dağıtımı eşit olmayan bir şekilde arttırır. Bundan kaçınmak için eşlemeyi döndüren bir durum makinesi gibi bir şeye ihtiyacınız vardır. 6,7 1,2 ile 1,2 ve 3,4 ile 5,0 ile eşleşir ve devam eder. Ne zaman gelseler de 6,7 atabiliriz. Her neyse, bu bir kütüphane uygulama problemidir.
FranG

-1

Başka bir yaklaşım: Yapma.

Yerine:

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;

Temel olarak, bir üçgen atın. Bir üçgenin alanı basittir ve böylece geri kalanın segment sayısını bir azalttık. Kalan bir üçgen olana kadar tekrarlayın.


2
Gauss'un Ayakkabı Bağı formülü, bunun için hesaplama sayısını yarıya ya da üçte bir kısayoludur. Çalışın.
Pieter Geerkens
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.