Bir nokta ile eksene hizalanmış bir dikdörtgen arasındaki mesafeyi nasıl hesaplarım?


29

X, y konumu, yükseklik ve genişliğe ve yakınlarda rastgele konumlandırılmış bir noktaya sahip bir 2B dikdörtgenim var.

Bu noktanın belirli bir mesafeden daha yakınsa, dikdörtgene çarpışıp çarpışmadığını kontrol etmenin bir yolu var mı? Bahsedilen dikdörtgenle çarpışan o noktanın dışında görünmez bir yarıçap hayal edin. Bununla ilgili bir sorunum yok çünkü bu bir kare değil!

Yanıtlar:


26

Eğer (x,y)dikdörtgenin merkezidir, bir noktadan kare uzaklık (px,py)dikdörtgenin sınırına bu şekilde hesaplanabilir:

dx = max(abs(px - x) - width / 2, 0);
dy = max(abs(py - y) - height / 2, 0);
return dx * dx + dy * dy;

Bu kare uzaklık sıfır ise, noktanın dokunduğu veya dikdörtgenin içinde olduğu anlamına gelir.


6
Merak eden herkes için (x, y) köşenin değil dikdörtgenin merkezidir
Greg Rozmarynowycz

2
Eski yorum için üzgünüm, fakat bu denklem dikdörtgenin eksen hizalı olduğunu varsayar mı?
BitNinja

1
@BitNinja evet, sorunun varsaydığı şey bu. Eksen hizalı değilse, en hızlı / en basit algoritma dikdörtgen bilgisinin nasıl depolandığına bağlı olacaktır.
sam hocevar

Diyelim ki nokta (4: 4), dikdörtgen (5: 5) genişlikte / yükseklikte (5: 5). Kodunuz, noktanın dikdörtgenin içine değdiğini veya içinde olduğunu iddia eder ancak açık bir şekilde dışarısı
LRN

@LRN, genişlik / yükseklik (5: 5) (2.5: 2.5) ila (7.5: 7.5) arasında uzanan (5: 5) ortalanmış bir dikdörtgendir. Nokta (4: 4) bu dikdörtgenin içindedir.
sam hocevar

11

Dikdörtgenin Eksen Hizalanmış olduğunu varsayıyorum.

Sadece noktayı dikdörtgenin içine sıkıştırmanız ve ardından kenetlenen noktadan mesafeyi hesaplamanız gerekir.

Nokta = (px, py), Dikdörtgen = (rx, ry, rwidth, rheight) // (sol üst köşe, boyutlar)

function pointRectDist (px, py, rx, ry, rwidth, rheight)
{
    var cx = Math.max(Math.min(px, rx+rwidth ), rx);
    var cy = Math.max(Math.min(py, ry+rheight), ry);
    return Math.sqrt( (px-cx)*(px-cx) + (py-cy)*(py-cy) );
}

3

Bunun için daire dikdörtgen çarpışmaları kullanmalısınız. Bir var benzer Yığın taşması soru.

Çevrenizin merkezi söz konusu olan nokta ve yarıçapı kontrol etmek istediğiniz mesafe olacaktır.


3

Bir noktadan dikdörtgenin kenarına kadar olan mesafeyi anlamaya çalışıyorsanız, dikdörtgenin oluşturduğu dokuz bölgenin her biriyle çalışmak en hızlı yol olabilir:

function pointRectangleDistance(x, y, x1, y1, x2, y2) {
    var dx, dy;
    if (x < x1) {
        dx = x1 - x;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else if (x > x2) {
        dx = x - x2;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else {
        if (y < y1) {
            return y1 - y;
        }
        else if (y > y2) {
            return y - y2;
        }
        else {
            return 0.0; // inside the rectangle or on the edge
        }
    }
}

2

[Yorumlara göre değiştirilmiş cevap]

Eğer aşağıdaki resimde gri dikdörtgen varsa, noktanın 10 birim içinde olup olmadığını görmek istiyorsanız, noktanın herhangi birinde olup olmadığını kontrol edin.

  1. kırmızı dikdörtgen
  2. Mavi dikdörtgen
  3. yeşil dairelerin herhangi biri (yarıçap 10)

görüntü tanımını buraya girin

inside=false;

bluerect.x=oldrect.x-10;
bluerect.y=oldrect.y;
bluerect.width=oldrect.width;
bluerect.height=oldrect.height+20;

if(  point.x >=bluerect && point.x <=redrect.x+bluerect.width &&
     point.y >=bluerect && point.y <=redrect.y+bluerect.height){
         //now point is side the blue rectangle
         inside=true;
}

redrect.x=oldrect.x;
redrect.y=oldrect.y-10;
redrect.width=oldrect.width+20;
redrect.height=oldrect.height;

if(  point.x >=redrect&& point.x <=redrect.x+redrect.width &&
     point.y >=redrect&& point.y <=redrect.y+redrect.height){
         //now point is side the redrectangle
         inside=true;
}


d1= distance(point, new point(oldrect.x, oldrect.y)) //calculate distance between point and (oldrect.x, oldrect.y)
d2= distance(point, new point(oldrect.x+10, oldrect.y))
d3= distance(point, new point(oldrect.x, oldrect.y+10))
d4= distance(point, new point(oldrect.x+10, oldrect.y+10))
if (d1 < 10 || d2 <10 || d3 < 10 || d4 <10){
    inside=true;
}

//inside is now true if the point is within 10 units of rectangle

Bu yaklaşım biraz tuhaf. Dikdörtgen simetri kullanarak 4 köşenin de test edilmesini önleyen benzer bir yöntem burada istifleme akışında belgelenmiştir .


Köşegen yönde bu, örneğin olan noktalara yanlış bir pozitif verecektir. 11 birim uzakta.
Eric B

Güncellenen resim kesinlikle yanlıştır, aslında hata durumunu gösterir ve doğru görünmesini sağlar. Bu yeşil nokta 10 birimden daha uzakta olabilir ve bu dış dikdörtgenin içinde olabilir.
Eric B

Hey @EricB, belirttiğiniz hatayı düzelttim, aşağı oyunuzu geri almaya ne dersiniz?
Ken

Cevabınız artık kesinlikle yanlış sonuçlar vermeyecek, bu yüzden aşağı oyu kaldırdım, ancak bu da en iyi yol değil. Neden merkezin dikdörtgenin içinde olup olmadığını ve dört çizgi segmenti daireyle kesişip kesişmediğini test etmiyorsunuz? Bu yeni dikdörtgen ve dairelerin inşası gerekli değildir. Cevabınız ayrıca noktadan dikdörtgene gerçek mesafeyi sağlamıyor.
Eric B

Bu cevap gerçekten korkunç. 12 ekleme, 4 nesne yapısı, 12 test, aslında 3 satır kod gerektiren bir görev için 4 kare kök?
sam hocevar

-2

Böyle bir şey kullanabilirsiniz: görüntü tanımını buraya girin


Bu yöntem gereksiz yere karmaşık görünüyor. Bu sorunu çözmek için x1 ve y1'i bulmak gerekli değildir.
Eric B

Aslında bu, belli bir mesafede bir çarpışma bulma gereksinimini bile karşılamıyor. Bu, noktanın dikdörtgenin içinde olup olmadığını tespit etmenin kötü bir yoludur.
Eric B

Örtülü bir mesafe ölçüsü zaten orada. if (d2 <10 * 10) {/ * 10 ölçü biriminde * /}
AlexanderBrevig
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.