Bir noktanın döndürülmüş bir dikdörtgenin içinde olup olmadığını nasıl verimli bir şekilde kontrol edebilirim?


11

Optimizasyon uğruna bir kısmı, öğrenme amaçlı bir kısmı, sormaya cesaret edeceğim: Bir 2D noktasının C # veya C ++ kullanarak P2D döndürülmüş bir dikdörtgen içinde olup olmadığını en verimli şekilde nasıl kontrol edebilirim XYZW?

Şu anda, Gerçek Zamanlı Çarpışma Algılama kitabında bulunan "üçgende nokta" algoritması kullanmak ve iki kez çalıştırmak (dikdörtgeni oluşturan iki üçgen için, örneğin XYZ ve XZW):

bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
 // Compute vectors        
 Vector2 v0 = C - A;
 Vector2 v1 = B - A;
 Vector2 v2 = P - A;

 // Compute dot products
 float dot00 = Vector2.Dot(v0, v0);
 float dot01 = Vector2.Dot(v0, v1);
 float dot02 = Vector2.Dot(v0, v2);
 float dot11 = Vector2.Dot(v1, v1);
 float dot12 = Vector2.Dot(v1, v2);

 // Compute barycentric coordinates
 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
 float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
 float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

 // Check if point is in triangle
 if(u >= 0 && v >= 0 && (u + v) < 1)
    { return true; } else { return false; }
}


bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
 if(PointInTriangle(X,Y,Z,P)) return true;
 if(PointInTriangle(X,Z,W,P)) return true;
 return false;
}

Ancak, daha temiz ve daha hızlı bir yol olabileceğini hissediyorum. Özellikle, matematik işlem sayısını azaltmak için.


Çok puanınız var mı, yoksa çok sayıda dikdörtgen var mı? Bu kadar küçük bir görevi optimize etmeye çalışmadan önce kendinize sormanız gereken ilk soru budur.
sam hocevar

İyi bir nokta. Çok fazla puanım olacak, ancak kontrol etmek için daha fazla dikdörtgen olacak.
Louis15

Bir noktanın döndürülmüş bir dikdörtgene mesafesini bulma ile ilgili soru . Bu dejenere bir durumdur (sadece mesafe 0 olduğunda kontrol edilir). Tabii ki, burada geçerli olmayan orada olmayan optimizasyonlar olacak.
Anko

Noktayı dikdörtgenin referans çerçevesine döndürmeyi düşündünüz mü?
Richard Tingle

@RichardTingle Aslında başında değildim. Daha sonra yaptım, çünkü bunun aşağıda verilen cevaplardan biri ile ilgili olduğunu düşünüyorum. Ama sadece açıklığa kavuşturmak için: önerdiğiniz şeyde, noktayı dikdörtgenlerin referans çerçevesine döndürdükten sonra, yalnızca max.x, min.x, vb.
Louis15

Yanıtlar:


2

Kolay ve anlaşılır bir optimizasyon aşağıdaki durumlarda son koşulu değiştirmek olacaktır PointInTriangle:

bool PointInRectangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P) {
  ...
  if(u >= 0 && v >= 0 && u <= 1 && v <= 1)
      { return true; } else { return false; }
  }
}

kod PointInRectanglezaten çoktan vardı, koşul (u + v) < 1dikdörtgen "ikinci" üçgen içinde olup olmadığını kontrol etmek için vardı.

Alternatif olarak, isLeftdört kez (sayfadaki ilk kod örneği, ayrıca büyük ölçüde açıklanmıştır) testi yapabilir ve hepsinin aynı işareti (sonuçların saat yönünde mi yoksa saat yönünün tersine mi verildiğine bağlı) döndürüp döndürmediğini kontrol edebilirsiniz. içeride olması gereken nokta. Bu, diğer tüm dışbükey çokgenler için de geçerlidir.

float isLeft( Point P0, Point P1, Point P2 )
{
    return ( (P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y) );
}
bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
    return (isLeft(X, Y, P) > 0 && isLeft(Y, Z, P) > 0 && isLeft(Z, W, P) > 0 && isLeft(W, X, p) > 0);
}

Süper. Benim önerimden çok daha hızlı ve çok daha zarif olan öneriyi beğenip beğenmediğimi veya PointInTri kodumun kolayca bir PointInRec olabileceğini fark ettiğinizi bilmiyorum! Teşekkürler
Louis15

isLeftYöntem için +1 . Vector2.Dotİşleri çok hızlandıran trig fonksiyonları (olduğu gibi) gerektirmez .
Anko

Btw, isLeft'i doğrudan ana fonksiyona ekleyerek ve "&&" operatörlerini "||" ters mantık mı? public static bool PointInRectangle(Vector2 P, Vector2 X, Vector2 Y, Vector2 Z, Vector2 W) { return !(( (Y.x - X.x) * (P.y - X.y) - (P.x - X.x) * (Y.y - X.y) ) < 0 || ( (Z.x - Y.x) * (P.y - Y.y) - (P.x - Y.x) * (Z.y - Y.y) ) < 0 || ( (W.x - Z.x) * (P.y - Z.y) - (P.x - Z.x) * (W.y - Z.y) ) < 0 || ( (X.x - W.x) * (P.y - W.y) - (P.x - W.x) * (X.y - W.y) ) < 0 ); }
Louis15

1
@ Louis15 Gerektiğini sanmıyorum - hem && ve || bir negatif / pozitif bulunursa (veya başka bir neden varsa?) başka ifadeler yürütmeyi durdurur. isLeftSatır içi olarak bildirmek , derleyicinin sizin için benzer bir şey yapacağını (ve muhtemelen daha iyi olabilir, çünkü derleyiciyi yazan mühendisler CPU'ları en iyi biliyordu, en hızlı seçenek ne olursa olsun) kodunuzu aynı veya daha iyi bir efektle daha okunabilir hale getirdi.
wondra

8

Düzenleme: OPs yorum rastgele bir 2D nokta döndürülmüş ve / veya hareketli bir dikdörtgen içinde olup olmadığını kontrol etmek için algoritmayı geliştirmek için önerilen negatif dairesel bağlı kontrol etkinliği hakkında şüpheci olmuştur. 2D oyun motorumda (OpenGL / C ++) biraz uğraşırken, cevabımı OP'nin mevcut dikdörtgen-nokta-nokta kontrol algoritmalarına (ve varyasyonlarına) karşı bir performans ölçütü sağlayarak yanıtımı tamamlıyorum.

Başlangıçta algoritmayı yerinde bırakmayı önerdim (neredeyse optimal olduğu için), ancak sadece oyun mantığı ile basitleştirin: (1) orijinal dikdörtgenin etrafında önceden işlenmiş bir daire kullanarak; (2) bir mesafe kontrolü yapın ve noktanın verilen daire içinde olup olmadığını; (3) OP'leri veya diğer herhangi bir basit algoritmayı kullanın (başka bir cevapta belirtildiği gibi isLeft algoritmasını öneririm). Benim önerimin arkasındaki mantık, bir noktanın daire içinde olup olmadığını kontrol etmenin, döndürülmüş bir dikdörtgenin veya başka bir çokgenin sınır kontrolünden önemli ölçüde daha verimli olmasıdır.

Bir karşılaştırma testi için ilk senaryom, yaklaşık 20 dönen / hareketli kareyle doldurulacak kısıtlı bir alanda çok sayıda görünen ve kaybolan nokta (her oyun döngüsünde değişen) çalıştırmaktır. Gösterim amacıyla bir video ( youtube bağlantısı ) yayınladım . Parametrelere dikkat edin: rastgele görünen noktaların sayısı, sayı veya dikdörtgenler. Aşağıdaki parametrelerle kıyaslayacağım:

KAPALI : Daire sınır negatif kontrolleri olmadan OP tarafından sağlanan basit algoritma

AÇIK : Dikdörtgenlerin etrafında işlenen (sınır) çevrelerin ilk hariç tutma denetimi olarak kullanılması

AÇIK + Yığın : Yığın üzerindeki döngü içinde çalışma zamanında daire sınırları oluşturma

ON + Kare Mesafesi : Daha pahalı karekök algoritmasını (Pieter Geerkens) kullanmaktan kaçınmak için kare mesafelerini daha fazla optimizasyon olarak kullanmak.

Burada, döngü boyunca yinelenen süreyi göstererek farklı algoritmaların çeşitli performanslarının bir özeti bulunmaktadır.

resim açıklamasını buraya girin

X ekseni, daha fazla nokta ekleyerek (ve böylece döngüyü yavaşlatarak) artan karmaşıklığı gösterir. (Örneğin, 20 dikdörtgen içeren gizli bir alanda 1000 rastgele görünen nokta denetiminde, döngü yinelenir ve algoritmayı 20000 kez çağırır.) Y ekseni, yüksek bir çözünürlük kullanarak tüm döngüyü tamamlamak için geçen süreyi (ms) gösterir performans zamanlayıcısı. Düzgün bir animasyon enterpolasyonu yapmak için yüksek fps'den yararlanamayacağı ve oyun zaman zaman 'engebeli' görünebileceği için 20 ms'den fazla iyi bir oyun için sorunlu olacaktır.

Sonuç 1 : Döngü içinde hızlı negatif kontrole sahip önceden işlenmiş dairesel bağlı bir algoritma, performansı normal algoritmaya kıyasla% 1900 artırır (orijinal döngü süresinin% 5'i kontrolsüz). Sonuç, bir döngü içindeki yineleme sayısı ile yaklaşık olarak orantılıdır, bu nedenle 10 veya 10000 rastgele görünen noktayı kontrol etmemiz önemli değildir. Böylece, bu çizimde, bir performans kaybı hissetmeden nesne sayısını güvenli bir şekilde 10k'a çıkarabilir.

Sonuç 2 : Önceki bir yorumda algoritmanın daha hızlı ancak bellek yoğun olabileceği ileri sürülmüştür. Bununla birlikte, önceden işlenmiş daire boyutu için bir kayan nokta saklamanın sadece 4 bayt aldığını unutmayın. OP eşzamanlı olarak 100.000'den fazla nesneyi çalıştırmayı planlamadığı sürece bu gerçek bir sorun oluşturmamalıdır. Alternatif ve bellek açısından verimli bir yaklaşım, döngü içindeki yığın üzerindeki çember maksimum boyutunu hesaplamak ve her yineleme ile kapsam dışı kalmasını sağlamak ve böylece bilinmeyen bir hız fiyatı için neredeyse hiç bellek kullanımı olmamasıdır. Aslında, sonuç bu yaklaşımın önceden işlenmiş bir daire boyutu kullanmaktan daha yavaş olduğunu, ancak yine de% 1150 civarında önemli bir performans artışı (yani orijinal işlem süresinin% 8'i) gösterdiğini göstermektedir.

Sonuç 3 : Gerçek mesafeler yerine kare mesafeler kullanarak ve dolayısıyla hesaplama açısından pahalı bir karekök işlemi yaparak sonuç 1 algoritmasını daha da geliştiriyorum. Bu sadece performansı hafifçe artırır (% 2400). (Not: Benzer ama biraz daha kötü bir sonuçla kare kök yaklaşımları için önceden işlenmiş diziler için karma tabloları da deniyorum)

Sonuç 4 : Dikdörtgenin hareket etmesini / çarpışmasını ayrıca kontrol ediyorum; ancak, mantıksal kontrol esasen aynı kaldığından, bu temel sonuçları (beklendiği gibi) değiştirmez.

Sonuç 5 : Dikdörtgen sayısını değiştiriyorum ve algoritmanın, alan dolduğunda daha az kalabalık (demoda gösterilmiyor) daha da verimli hale geldiğini görüyorum. Bir nokta ile nesnenin sınırları arasındaki küçük alanda görünme olasılığı azaldıkça sonuç da biraz beklenir. Diğer uçta, aynı sınırlı küçük alanda çok fazla dikdörtgen sayısını artırmaya ve döngü içinde (sin (iterator)) çalışma zamanında boyut olarak dinamik olarak değiştirmeye çalışıyorum. Bu hala performansta% 570 (veya orijinal döngü süresinin% 15'i) artmasıyla son derece iyi performans gösterir.

Sonuç 6 : Burada önerilen alternatif algoritmaları test ediyorum ve performansta çok hafif ama önemli olmayan bir fark buluyorum (% 2). İlginç ve daha basit IsLeft algoritması,% 17 (orijinal hesaplama süresinin% 85'i) performans artışı ile çok iyi bir performans sergiliyor, ancak hızlı bir negatif kontrol algoritmasının verimliliğine yakın bir yerde yok.

Demek istediğim, özellikle sınırlar ve çarpışma olaylarıyla uğraşırken önce yalın tasarım ve oyun mantığını düşünmektir. OP'nin mevcut algoritması zaten oldukça verimlidir ve başka bir optimizasyon, temel kavramın kendisini optimize etmek kadar kritik değildir. Dahası, bir algoritmanın verimliliği kritik olarak onlara bağlı olduğundan, oyunun kapsamını ve amacını iletmek iyidir.

Sadece düz koda bakmak gerçek çalışma zamanı performansı hakkındaki gerçeği ortaya çıkaramayabileceğinden, oyun tasarımı aşamasında herhangi bir karmaşık algoritmayı karşılaştırmaya çalışmayı öneririm. Örneğin, fare imlecinin bir dikdörtgen içinde olup olmadığını test etmek isterse veya nesnelerin çoğunluğu zaten dokunuyorsa, önerilen algoritma burada bile gerekli olmayabilir. Nokta kontrollerinin çoğunluğu dikdörtgen içindeyse, algoritma daha az verimli olacaktır. (Ancak, ikincil negatif kontrol olarak bir 'iç daire' sınırı oluşturmak mümkün olacaktır.) Daire / küre sınır kontrolleri, aralarında doğal olarak bir miktar boşluk bulunan çok sayıda nesnenin düzgün çarpışma tespiti için çok yararlıdır. .

Rec Points  Iter    OFF     ON     ON_Stack     ON_SqrDist  Ileft Algorithm (Wondra)
            (ms)    (ms)    (ms)    (ms)        (ms)        (ms)
20  10      200     0.29    0.02    0.04        0.02        0.17
20  100     2000    2.23    0.10    0.20        0.09        1.69
20  1000    20000   24.48   1.25    1.99        1.05        16.95
20  10000   200000  243.85  12.54   19.61       10.85       160.58

Her ne kadar olağandışı yaklaşımı sevsem ve Da Vinci referansını sevsem de, yarıçapın yanı sıra çevrelerle uğraşmanın o kadar verimli olacağını düşünmüyorum. Ayrıca, bu çözüm sadece tüm dikdörtgenler sabit ve önceden biliniyorsa makul
Louis15

Dikdörtgenin konumunun sabitlenmesi gerekmez. Göreli koordinatları kullanın. Bunu da böyle düşün. Bu yarıçap, dönüş ne olursa olsun aynı kalır.
Majte

Bu harika bir cevap; daha da iyisi çünkü hiç düşünmemiştim. Kare mesafeleri gerçek mesafelerin yerine kullanmanın yeterli olduğunu ve kare kök hesaplama gereksinimini koruduğunu not etmek isteyebilirsiniz.
Pieter Geerkens

Hızlı pozitif / negatif test için ilginç bir algoritma! Sorun, önceden işlenmiş sınırlayıcı daireleri (ve genişlikleri) kaydetmek için fazladan bellek olabilir, iyi sezgisel olabilir, ancak sınırlı bir kullanıma da sahip olduğunu unutmayın - çoğunlukla belleğin çok önemli olmadığı durumlarda (daha büyük nesnelerdeki statik boyutlu dikdörtgenler = hareketli oyun nesneleri) ve ön işlem için zaman ayırın.
wondra

Düzenlendi + karşılaştırma testi eklendi.
Majte

2

4 noktalı bir dikdörtgen tanımlamak yamuk yapmayı mümkün kılar. Bununla birlikte, x, y, genişlik, yükseklik ve ortası etrafında bir döndürme ile tanımlarsanız, kontrol ettiğiniz noktayı dikdörtgenin ters dönüşüyle ​​(aynı orijin etrafında) döndürebilir ve ardından orijinal dikdörtgenin içinde.


Hmm, öneri için teşekkürler, ancak döndürme ve ters dönüşü elde etmek o kadar verimli görünmüyor. Aslında benim çözümüm kadar verimli olmayacak
wondra'dan

Bir 3B noktayı bir matrisle döndürmenin 6 çarpma ve 3 toplama ve bir işlev çağrısı olduğunu fark edebilirsiniz. @ wondra'nın çözümü en iyi eşdeğerdir, ancak niyette çok daha az nettir; ve
DRY'yi

@Pieter Geerkens interseting iddiası, çözümlerimden herhangi biri DRY'yi nasıl ihlal ediyor (ve DRY temel programlama ilkelerinden biri mi? Şimdiye kadar hiç duymadım)? Ve en önemlisi, bu çözümlerin hangi hataları var? Her zaman öğrenmeye hazır.
wondra

@wondra: DRY = Kendinizi Tekrarlama. Kod snippet'iniz, standart bir matris uygulamasından-Vector yöntemini çağırmak yerine, işlevsellik kodda her yerde göründüğü her yerde bir matrisin ayrıntılarını vektör çarpımı ile kodlamayı önerir.
Pieter Geerkens

@PieterGeerkens tabii ki sadece bir kısmını öneriyoruz - 1) açıkça matrisiniz yok (her sorgu için yeni matris tahsis etmek performansa çok fazla çarptı) bir. Düşük seviyeli bir işlemdir ve beklenmedik davranışları önlemek için kapsüllenmiş olarak kalmalıdır.
wondra

1

Bunu kıyaslamak için zamanım yoktu, ama benim önerim, dikdörtgeni x ve y aralığında 0 ile 1 aralığında eksene hizalanmış kareye dönüştüren dönüşüm matrisini saklamak olurdu. dikdörtgenin bir köşesini (0,0) ve diğer köşesini (1,1) olarak dönüştürür.

Dikdörtgen çok fazla hareket ettirilirse ve çarpışma nadiren kontrol edilirse, elbette daha pahalı olurdu, ancak dikdörtgenin güncellemelerinden çok daha fazla kontrol varsa, en azından iki üçgene karşı orijinal test yaklaşımından daha hızlı olurdu, çünkü altı noktalı ürünler bir matris çarpımı ile değiştirilir.

Ancak her zaman olduğu gibi, bu algoritmanın hızı büyük ölçüde gerçekleştirilmesini beklediğiniz kontrol türlerine bağlıdır. Noktaların çoğu basit bir mesafe kontrolü gerçekleştiren dikdörtgene bile yakın değilse (örn. (Point.x - firstCorner.x)> aLargeDistance) büyük bir hızlanmaya neden olabilirken, hemen hemen hepsi noktalar dikdörtgenin içinde.

EDIT: Bu benim Rectangle sınıf benim gibi olurdu:

class Rectangle
{
public:
    Matrix3x3 _transform;

    Rectangle()
    {}

    void setCorners(Vector2 p_a, Vector2 p_b, Vector2 p_c)
    {
        // create a matrix from the two edges of the rectangle
        Vector2 edgeX = p_b - p_a;
        Vector2 edgeY = p_c - p_a;

        // and then create the inverse of that matrix because we want to 
        // transform points from world coordinates into "rectangle coordinates".
        float scaling = 1/(edgeX._x*edgeY._y - edgeY._x*edgeX._y);

        _transform._columns[0]._x = scaling * edgeY._y;
        _transform._columns[0]._y = - scaling * edgeX._y;
        _transform._columns[1]._x = - scaling * edgeY._x;
        _transform._columns[1]._y = scaling * edgeX._x;

        // the third column is the translation, which also has to be transformed into "rectangle space"
        _transform._columns[2]._x = -p_a._x * _transform._columns[0]._x - p_a._y * _transform._columns[1]._x;
        _transform._columns[2]._y = -p_a._x * _transform._columns[0]._y - p_a._y * _transform._columns[1]._y;
    }

    bool isInside(Vector2 p_point)
    {
        Vector2 test = _transform.transform(p_point);
        return  (test._x>=0)
                && (test._x<=1)
                && (test._y>=0)
                && (test._y<=1);
    }
};

Bu benim kıyaslamamın tam listesi:

#include <cstdlib>
#include <math.h>
#include <iostream>

#include <sys/time.h>

using namespace std;

class Vector2
{
public:
    float _x;
    float _y;

    Vector2()
    :_x(0)
    ,_y(0)
    {}

    Vector2(float p_x, float p_y)
        : _x (p_x)
        , _y (p_y)
        {}

    Vector2 operator-(const Vector2& p_other) const
    {
        return Vector2(_x-p_other._x, _y-p_other._y);
    }

    Vector2 operator+(const Vector2& p_other) const
    {
        return Vector2(_x+p_other._x, _y+p_other._y);
    }

    Vector2 operator*(float p_factor) const
    {
        return Vector2(_x*p_factor, _y*p_factor);
    }

    static float Dot(Vector2 p_a, Vector2 p_b)
    {
        return (p_a._x*p_b._x + p_a._y*p_b._y);
    }
};

bool PointInTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
 // Compute vectors        
 Vector2 v0 = C - A;
 Vector2 v1 = B - A;
 Vector2 v2 = P - A;

 // Compute dot products
 float dot00 = Vector2::Dot(v0, v0);
 float dot01 = Vector2::Dot(v0, v1);
 float dot02 = Vector2::Dot(v0, v2);
 float dot11 = Vector2::Dot(v1, v1);
 float dot12 = Vector2::Dot(v1, v2);

 // Compute barycentric coordinates
 float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
 float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
 float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

 // Check if point is in triangle
 if(u >= 0 && v >= 0 && (u + v) < 1)
    { return true; } else { return false; }
}


bool PointInRectangle(Vector2 X, Vector2 Y, Vector2 Z, Vector2 W, Vector2 P)
{
 if(PointInTriangle(X,Y,Z,P)) return true;
 if(PointInTriangle(X,Z,W,P)) return true;
 return false;
}

class Matrix3x3
{
public:
    Vector2 _columns[3];

    Vector2 transform(Vector2 p_in)
    {
        return _columns[0] * p_in._x + _columns[1] * p_in._y + _columns[2];
    }
};

class Rectangle
{
public:
    Matrix3x3 _transform;

    Rectangle()
    {}

    void setCorners(Vector2 p_a, Vector2 p_b, Vector2 p_c)
    {
        // create a matrix from the two edges of the rectangle
        Vector2 edgeX = p_b - p_a;
        Vector2 edgeY = p_c - p_a;

        // and then create the inverse of that matrix because we want to 
        // transform points from world coordinates into "rectangle coordinates".
        float scaling = 1/(edgeX._x*edgeY._y - edgeY._x*edgeX._y);

        _transform._columns[0]._x = scaling * edgeY._y;
        _transform._columns[0]._y = - scaling * edgeX._y;
        _transform._columns[1]._x = - scaling * edgeY._x;
        _transform._columns[1]._y = scaling * edgeX._x;

        // the third column is the translation, which also has to be transformed into "rectangle space"
        _transform._columns[2]._x = -p_a._x * _transform._columns[0]._x - p_a._y * _transform._columns[1]._x;
        _transform._columns[2]._y = -p_a._x * _transform._columns[0]._y - p_a._y * _transform._columns[1]._y;
    }

    bool isInside(Vector2 p_point)
    {
        Vector2 test = _transform.transform(p_point);
        return  (test._x>=0)
                && (test._x<=1)
                && (test._y>=0)
                && (test._y<=1);
    }
};

void runTest(float& outA, float& outB)
{
    Rectangle r;
    r.setCorners(Vector2(0,0.5), Vector2(0.5,1), Vector2(0.5,0));

    int numTests = 10000;

    Vector2 points[numTests];

    Vector2 cornerA[numTests];
    Vector2 cornerB[numTests];
    Vector2 cornerC[numTests];
    Vector2 cornerD[numTests];

    bool results[numTests];
    bool resultsB[numTests];

    for (int i=0; i<numTests; ++i)
    {
        points[i]._x = rand() / ((float)RAND_MAX);
        points[i]._y = rand() / ((float)RAND_MAX);

        cornerA[i]._x = rand() / ((float)RAND_MAX);
        cornerA[i]._y = rand() / ((float)RAND_MAX);

        Vector2 edgeA;
        edgeA._x = rand() / ((float)RAND_MAX);
        edgeA._y = rand() / ((float)RAND_MAX);

        Vector2 edgeB;
        edgeB._x = rand() / ((float)RAND_MAX);
        edgeB._y = rand() / ((float)RAND_MAX);

        cornerB[i] = cornerA[i] + edgeA;
        cornerC[i] = cornerA[i] + edgeB;
        cornerD[i] = cornerA[i] + edgeA + edgeB;
    }

    struct timeval start, end;

    gettimeofday(&start, NULL);
    for (int i=0; i<numTests; ++i)
    {
        r.setCorners(cornerA[i], cornerB[i], cornerC[i]);
        results[i] = r.isInside(points[i]);
    }
    gettimeofday(&end, NULL);
    float elapsed = (end.tv_sec - start.tv_sec)*1000;
    elapsed += (end.tv_usec - start.tv_usec)*0.001;
    outA += elapsed;

    gettimeofday(&start, NULL);
    for (int i=0; i<numTests; ++i)
    {
        resultsB[i] = PointInRectangle(cornerA[i], cornerB[i], cornerC[i], cornerD[i], points[i]);
    }
    gettimeofday(&end, NULL);
    elapsed = (end.tv_sec - start.tv_sec)*1000;
    elapsed += (end.tv_usec - start.tv_usec)*0.001;
    outB += elapsed;
}

/*
 * 
 */
int main(int argc, char** argv) 
{
    float a = 0;
    float b = 0;

    for (int i=0; i<5000; i++)
    {
        runTest(a, b);
    }

    std::cout << "Result: " << a << " / " << b << std::endl;

    return 0;
}

Kod kesinlikle güzel değil, ama hemen herhangi bir büyük hata görmüyorum. Bu kod ile dikdörtgen her kontrol arasında hareket ettirilirse benim çözüm yaklaşık iki kat daha hızlı olduğunu gösteren sonuçlar elde. Hareket etmezse, kodum beş kat daha hızlı görünüyor.

Kodun nasıl kullanılacağını biliyorsanız, dönüşümü ve kontrolleri iki boyuta ayırarak kodu biraz daha hızlandırabilirsiniz. Örneğin bir yarış oyununda, sürüş yönünü işaret eden ilk koordinatı kontrol etmek muhtemelen daha hızlı olacaktır, çünkü birçok engel aracın önünde veya arkasında olacaktır, ancak neredeyse hiç sağ veya sol olmayacaktır.


İlginç, ancak matris dönüşünü noktalara da uygulamanız gerektiğini unutmayın. Oyun motorumda bir matris çürüme operasyonum var ve daha sonra algoritmanızı kıyaslayabilirim. Son yorumunuzla ilgili olarak. Daha sonra bir 'iç daire' tanımlanmış olabilir ve noktanın yukarıda açıklanan şekilde iç dairenin dışında ve dış dairenin içinde olup olmadığını iki kez negatif kontrol edebilirsiniz.
Majte

Evet, çoğu noktanın üçgenin ortasına yakın olmasını beklerseniz bu yardımcı olacaktır. Karakterin içinde kalması gereken bir dış dikdörtgen ve dışarıda kalması gereken daha küçük bir iç dikdörtgen kullanarak dikdörtgen bir yol tanımladığınız dikdörtgen bir yarış pisti gibi bir durum hayal ediyordum. Bu durumda, her kontrol dikdörtgenin kenarlığına yakın olur ve bu daire kontrolleri muhtemelen performansı daha da kötüleştirir. Verilmiş, bu yapılandırılmış bir örnek, ama bunun gerçekte olabilecek bir şey olduğunu söyleyebilirim.
Lars Kokemohr

Böyle şeyler olabilir, evet. Algoritmaya karşı dönmenin tatlı noktası nedir acaba? Sonunda amacınıza kadar kaynar. Eğer zamanınız varsa, OPs postasını kullanarak kodunuzu gönderebilir ve algoritmanızı kıyaslayabilir miyim? Bakalım sezgilerinizin doğru olup olmadığını. Fikrinizin IsLeft Algoritmasına karşı performansını merak ediyorum.
Majte
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.