İki noktayla dikdörtgen tanımlamanın ardındaki fikir nedir? [kapalı]


15

Bu mantıklı değil, ama zamanın% 99'unda garip bir şekilde çalışıyor.

Genellikle 2D grafiklerde dikdörtgenler başlatılır, saklanır ve bir çift nokta olarak manipüle edilir. Belirli bir dilde,

class Rect:
   p1, p2: point

Bir dikdörtgeni iki x değeri ve iki y değeri olarak tanımlamak daha mantıklıdır:

class Rect
   xleft, xright: int
   ytop, ybottom: int

Kaynak kodun herhangi bir yerinde en üstteki y değerini kullanmak istiyorsanız, iki nokta ile rect.p1.y (hmmm, dur ve düşün, p1 veya p2) demelisiniz ama düz veri üyeleri olarak dört değerle, açık ve doğrudan: rect.ytop (düşünmeye gerek yok!) İki noktanın kullanılması, dikey ile uğraşırken yatay çizgiyi karıştırmanız gerektiği anlamına gelir; bağımsız öğeler arasında dışsal bir ilişki vardır.

Bu iki nokta fikri nasıl ortaya çıktı ve neden devam ediyor? Çıplak x ve y koordinatlarına göre bir faydası var mı?

EKLENEN NOT: Bu soru, çizim ve boyama uygulamasındaki rastgele şekiller bağlamında değil, Windows yöneticileri ve GUI araç takımları gibi XY hizalanmış dikdörtgenler bağlamındadır.


8
Rects kullanarak önemli miktarda kod yazdınız mı?

6
Bir dikdörtgen iki nokta ile tanımlanır, bu yüzden onları iki nokta olarak temsil etmek çok mantıklıdır.
Adam Crossland

2
Bir dikdörtgen daha doğal olarak x değerleri ve y değerleri aralığı olarak tanımlanır.
DarenW

2
Harika bir soru! Bunu hiç düşünmedim, ama ilginç bir argüman yapıyorsun FWIW, Windows'da sizin de tanımladığınız gibi bir RECT var (üst, sol, alt, sağ)
Dean Harding

3
İki noktalı bir dikdörtgeni nasıl tanımlarsınız? Rotasyon olmadığı var mı?
Nick T

Yanıtlar:


8

Hataya daha az eğilimli olduğunu düşündünüz mü?

(Nokta1, Nokta2) kullanırsanız, ne belirttiğiniz çok açıktır. 2 nokta sağlarsanız, olası tek hata, noktaların sırası önemli olmadığı için noktaları oluştururken kullanıcının x ve y değerlerini karıştırmasıdır.

4 tamsayı sağlarsanız, birileri dikkat etmiyorsa, istediğiniz zaman (x1, x2, y1, y2) (x1, y1, x2, y2) veya tam tersini sağlayabilir. Ayrıca, WCF'nin Rect yapısı gibi bazı API'ler , (x, y, genişlik, yükseklik) olarak bir dikdörtgen tanımlar ve bu da (1, 2, 3, 4) ne anlama geldiğinde karışıklığa neden olabilir. Bu (x, y, w, h) veya (x1, y1, x2, y2) veya (x1, x2, y1, y2) mı?

Sonuçta, (Point1, Point2) benim için biraz daha güvenli görünüyor.


3
Rect (xrange (x1, x2), yrange (y1, y2)) gibi bir şeye ne dersiniz? Bu, API kullanım güvenliği ve zarafetinde son noktadır.
DarenW

9

Her zaman bir dikdörtgenin nokta + genişlik ve yükseklik olarak tanımlanmasını sevdim, nokta dikdörtgenin sol üst köşesidir.

class Rect {
  float x, y;
  float width, height;
}

Ve sonra diğer metrikleri almak için ihtiyacınız olan yöntemleri ekleyin. Gibi Java sürümü


4
Üst y + yüksekliği, y yüksekliği veya sadece y mı?
Cameron MacFarland

2
@Cameron MacFarland: Bu, uygulamanın düşük bir dikdörtgeni ilgilendirmeyen koordinat sistemine bağlıdır.
Jon Purdy

2
@Martin Wickman: 2 puan kullanmanın avantajı nedir?
Kramii

@Kramii: Bir avantaj, tüm rektifi hareket ettiriyorsanız yalnızca bir noktayı çevirmek zorunda kalmanızdır. Btw, ihtiyacınız olduğunda her zaman "eksik noktayı" hesaplayabilirsiniz (cpu / bellek ödünleşimi).
Martin Wickman

Bu da gerçek hayatta görülür. Dikdörtgenlerle yaptığım en yaygın şeylerden birinin, içinde bir noktanın olup olmadığını test etmesi zor. Çizim de yaygındır. Her iki durumda da benim gibi yüksek performanslı saat döngüsü sayaçlarını rahatsız eden ilave işlemlerin yapılması gerekir.
DarenW

7

Aslında, bir rectagle 2 puanla tanımlanmaz. Bir dikdörtgen, eksenlere paralel olduğunda yalnızca iki nokta ile tanımlanabilir.

Eksenlere paralel olan dikdörtgenleri temsil etmenin birkaç yolu vardır:

  1. Çapraz olarak zıt iki nokta
  2. Bir köşe noktası, yükseklik ve genişlik
  3. Merkez noktası, yarım yükseklik ve genişlik (nadir, ancak bazen yararlıdır).
  4. İki X koordinatı ve iki Y koordinatı olarak

(1) için, birçok kütüphane hangi iki noktanın kullanıldığını belirlemek için bir kural kullanır - örneğin topLeft ve bottomRight.

Temsil seçimi, dikdörtgen tanımının orijinal amacı tarafından yönlendirilebilir, ancak bunun genellikle keyfi olduğunu hayal ediyorum . Temsiller, taşıdıkları bilgilerde eşdeğerdir. Bununla birlikte, dikdörtgenin özelliklerinin hesaplanma kolaylığı ve yeniden dikdörtgen üzerinde işlemlerin gerçekleştirilme kolaylığı açısından farklılık gösterirler.

Tanımın (1) diğerlerine göre avantajları:

  • API'nın diğer çokgenler, çizgiler vb. İle tutarlılığı
  • topLeft, bottomRight noktaları kabul eden herhangi bir yönteme geçirilebilir
  • Point sınıfı yöntemleri topLeft, bottomRight üzerinde çağrılabilir
  • Çoğu özellik kolayca türetilebilir, örn. Sol, üstSağ, genişlik, yükseklik, merkez, diyagonal uzunluk vb.

6

Peki p1: Pointve p2: Pointher ikisindeint de iki koordinat olacak , yani sınıfınız aynı şey değil mi?

Ve eğer bu iki noktayı birinci sınıf Pointnesneler olarak saklarsanız, onlardan biraz daha fazla faydalanamaz mısınız? Bildiğim çoğu grafik koordinat sisteminde, nesneler hiyerarşisi oluşturmak için noktalar bu şekilde alt sınıflara ayrılır: point -> circle -> ellipsevb.

PointSınıfı kullanmayan bir nesne yaparsanız, o nesneyi sınıf hiyerarşisinin geri kalanından ayırmış olursunuz.


1
OP'nin temsilini gördüğüm avantaj, bir dikdörtgenin düşük y değerini bilmek istiyorsanız, bunun "ybottom" olduğunu bilirsiniz, p1 / p2 ile hangisinin daha düşük olduğunu bulmanız gerekir. Bu zaten p1'in daha düşük değerler olacağını garanti etmezseniz.
Jason Viers

1
İki farklı yapı her ikisinin de dört koordinatla kaynatıldığı doğru olmakla birlikte, iki nokta versiyonu x'in bir y ve bir y toplayan, x'in hangi y ile gittiğine dair özel bir gerekçe olmaksızın yabancı bir seviye sunar. Bu ekstra seviyeyi, uzun yıllar grafik programlamanın ardından herhangi bir yardımcı program olarak görmüyorum.
DarenW

1
@ Jason: İyi nokta. Bununla birlikte, ytop/ ybottomyaklaşımıyla, ybottomaslında aşağıda olan bir yerde de bir garanti olması gerekir ytop.
Dr.Wily's Apprentice

Ya da onları em y1 ve y2 olarak adlandırın ve min (y1, y2) ve max (y1, y2) kullanın - tabii ki iki nokta p1, p2 üzerinden erişimden bile daha hantal olur.
DarenW

özellikle kodlamadığınız sürece, üst / alt adlandırma size hiçbir şey almaz. Bence sadece karışıklık katacak.
lkg

5

Bu yüzden Delphi'yi seviyorum TRect. Şu anda hangisi daha uygunsa, bir TopLeft ve bir BottomRight noktası veya Top, Sol, Alt ve Sağ tamsayı olarak yorumlanabilen bir varyant kaydı (C-konuşmada birleşik yapı) olarak tanımlanır.


1
Evet, çok kullanışlı bir özellik.
Orbling

4

Elbette, dikdörtgeni şöyle tanımlarsanız:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

o zaman hangi noktanın hangisi olduğunu hemen bilirsiniz.

Daha da iyisi, uygulamanız için ihtiyaç duyduğunuz şekilde dikdörtgeni değiştirmenize izin veren ekstra özellikler eklemek olacaktır. Bunlar, temeldeki veri yapısını güncelleyecektir.

Şekle bir dönüşüm ekleyerek, dikdörtgeni istediğiniz gibi yönlendirebilirsiniz. Hızlı kabul / reddetme kontrolleri için yine de eksenle hizalanmış bir sınırlama kutusuna ihtiyacınız vardır :)

Ancak, modeliniz bir dönüşüm uygulamadan herhangi bir yönde dikdörtgenlere izin veriyorsa, "sol alt" ve "sağ üst", "p1" ve "p2" (veya eşdeğeri) değerlerine geri dönüş anlamına gelmez.


Peki, dikdörtgeni 90 derece döndürdüğünüzde ne olur? Şimdi başlangıçta olduğundan iki farklı nokta mı izliyorsunuz, yoksa "topRight" şimdi "bottomLeft" in solunda mı?
Inaimathi

@Inaimathi - bir dönüşüm matrisi eklerseniz dikdörtgeni eksenlerle yönlendirebilirsiniz. Ancak, uygulamanıza bağlıdır.
ChrisF

2

bir dikdörtgenin bir x ve y boyutu ve bir nokta ile temsil edilmesi daha mantıklı olduğunu düşünüyorum; hatta konum noktasını dikdörtgenin merkezine dönüştürebilirsiniz, böylece dönüşten bağımsız olur

ama muhtemelen iki nokta olarak kodlamak en kolay yoldu!


İki nokta olarak kodlamak nasıl daha kolay olurdu?
DarenW

@DaremW: tipik dikdörtgen çizme kitaplığı işlevleri sol üst ve sağ alt noktaları bağımsız değişken olarak alır
Steven A. Lowe

Peki bu API neden bu şekilde tasarlanıyor? Akılsızca önceki kütüphaneleri taklit etmenin yanı sıra.
DarenW

@DarenW: Tahminimce kütüphaneler giriş olarak iki puan alan ve çok verimli olan bir Bresenham çizgi çizme rutini kullanıyorlardı
Steven A. Lowe

2

Bunu sevmiyorum çünkü aslında keyfi bir rotasyona izin veren potansiyel bir özgürlük derecesi attık. Genel bir 2B dikdörtgenin bilinmeyen beş derecesi vardır (serbestlik derecesi). Onları bir noktanın koordinatları, bu noktayla tepe noktası oluşturan iki kenarın uzunlukları ve ilk çizginin yatay kısmından (diğerinin 90 derece daha büyük bir açı olduğu varsayılır) olarak belirtebiliriz. Sonsuz sayıda başka olasılık da kullanılabilir, ancak belirtilmesi gereken beş bağımsız miktar vardır. Bazı seçimler, onlarla yapılanlara bağlı olarak diğerlerinden daha kolay cebire yol açacaktır.


5
"Standart" bir dikdörtgen yapının titizlikle tanımlanmış bir matematiksel dikdörtgen değil, her zaman X ve Y eksenlerine paralel olan basitleştirilmiş bir versiyon olduğunu anlamak önemlidir, çünkü çok özel bir şey için kullanılmak üzere yaratılmıştır: dikdörtgen bölgeleri tanımlama X ve Y eksenlerine (neredeyse) daima paralel olan bir pencere yöneticisi için.
Mason Wheeler

+1, sol / sağ / üst / alt yapı bildirilir ve bu nedenle daha az bilgi içerir
Javier

İyi nokta, yaklaşık xy hizalanmış dikdörtgenler. Aklıma gelmişti ve aynı zamanda 3D modellemede ve diğer bazı şeylerde kullanıldığı gibi uzanıyor, ancak tüm xy (belki de -z) hizalandı.
DarenW

1

Bu 2 puanla aynı şey değil mi? Bu nasıl garip ... çoğu çizim rutini ayrı x / y bileşenleri değil, noktalar gerektirir.


1

Dikdörtgenleri nokta çifti olarak tanımlamak, noktayı başka bir şekil için tepe noktası olarak yeniden kullanmanızı sağlar. Sadece bir düşünce...


Ancak, dört köşeli bir şekli tanımlamak için sadece iki noktayı tutmak gibi, yarım deste ile oynamak gibi görünüyor. Eğer sol üst, serin, ancak sağ üste ihtiyacınız varsa, göreceli olarak, bazı süslü veri yakalama yapmanız gerekir.
DarenW

nokta AX noktası BY ve nokta BX noktası AY olarak tanımlanan bir erişimci varsa, bellekte / diskte daha hafif hale getirir Bence çok sayıda tepe noktasının yarısını depolamayı ve sadece (maksimum ızgara boyutuna bağlı olarak) işaret etmeyi düşünüyorum. Sizin menzil düşüncelerinizle gittiğiniz yere ulaşıyorum, ancak destenin yarısı ile oynamıyorsunuz, sadece yinelenen veriler saklamıyorsunuz ... ve yapılması gereken diğer noktalar bellek kısıtlamaları nelerdir? birbirine bağlı tüm kodlarda rötuşları yeniden uygulama sonuçları nelerdir?
RobotHumans

ve ilk iki
tepe noktasını

1

Esas olarak tüm şekil ilkelleri arasında tekdüzelik oluşturmak olduğuna inanıyorum.

Elbette, dikdörtgeni birçok farklı şekilde tanımlayabilirsiniz, ancak bir üçgeni, bir yıldızı veya daireyi benzer veri yapılarını kullanabilecek şekilde nasıl tanımlarsınız?

Tüm çokgenler noktalarıyla tanımlanabilir, noktalarla ne yapılacağını belirlemek için kısa bir mantıkla tanımlanabilir.

Grafik kütüphaneleri öncelikle bu çokgenler üzerinde köşe ve kenarlar açısından çalışırlar, bu nedenle noktalar ve aralarındaki çizgiler, tüm hesaplamalar bu iki özellik üzerinde çalışır, iyi ve fasetler, ancak bu sadece kenarların bir fonksiyonudur.


1

İki boyutta, dikdörtgeni iki nokta olarak depolamak, belirli bir köşeyi ve bir genişlik ve yüksekliği tanımlamaktan daha açıktır - negatif genişlik veya yüksekliği veya her seçeneği diğerinden belirlemek için gereken hesaplamaları göz önünde bulundurun.

Noktalarla tanımlanan bir dikdörtgen üzerinde döndürme yapmak, nokta artı genişlik ve yükseklikte tanımlanmış olandan çok daha basittir.

Kapsüllemenin bu ayrımı sınıfın bir kullanıcısı olarak önemsiz hale getirmesini beklerdim.

Bir dikdörtgen 3 boyutta iyi tanımlanacak üç nokta olarak tanımlanmalıdır. 4 veya daha fazla boyutta bir dikdörtgen tanımlama gerekliliğinden tamamen emin değilim.


1

Tamamen keyfi. Dikdörtgen çizmek için dört bilgiye ihtiyacınız var. Kütüphane tasarımcıları bunu iki nokta ile (her biri xy koordinatıyla) göstermeye karar verdiler, ancak bunu x / y / w / h veya üst / alt / sol / sağ ile kolayca yapabilirler.

Bence OP'nin asıl sorusu şudur: bu özel seçim neden yapıldı?


1

Parametrelerin seçimi sadece düşük seviyeli tasarımcılar / kodlayıcılar için önemlidir.

Üst düzey kullanıcıların yalnızca şunları düşünmesi gerekir:

  • IsPointInRect
  • alan
  • Kavşak (veya Kırpma)
  • HasOverlap (Kesişim Alanı ile aynı> 0)
  • Birlik (dikdörtgenlerin listesi haline gelir)
  • Çıkarma (rektifi A'da olan ancak rektifi B'de olmayan aynı nokta kümesini temsil eden dikdörtgenlerin listesi)
  • dönüştürmek
    • X ve Y'deki değişimler
    • Döndürme (0, 90, 180, 270)
    • X ve Y'de ölçeklendirme (nota bakınız)
  • Xmin, Xmax, Ymin, Ymax, Genişlik, Yükseklik özellikleri için basit sözdizimi, kullanıcının tam parametre seçimini bilmesine gerek kalmaz.

Not: Ölçekleme dönüşümü sırasında hassasiyet kaybını en aza indirmek için, kayan nokta koordinatları kullanan ikinci bir Rect sınıfı uygulamak bazen uygundur, böylece ara sonuçlar bir dönüşüm dizisinde doğru bir şekilde saklanabilir ve yalnızca tamsayıya yuvarlanarak yuvarlanabilir son adım.


0

@Steven'in dediği gibi, bence bir (x, y) nokta ve (w, h) boyut vektörü cinsinden olması gerekir. Çünkü belirsizliğe düşmek kolaydır. (0,0) noktasından başlayarak aşağıdaki doldurulmuş dikdörtgene sahip olduğunuzu varsayalım.

  012
0 XXX
1 XXX
2 XXX

Açıkçası genişliği, yüksekliği (3,3), ama ikinci nokta nedir? (2,2) veya (3,3) mü?

Bu belirsizlik her türlü soruna neden olabilir.

Yıllar önce, grafik koordinatları , pikseller üzerinde bulunan çizgiler olarak değil, pikseller arasındaki çizgiler olarak düşünmenin daha iyi olduğunu öğrendim . Bu şekilde belirsizlik olmaz.


2
Mac'teki orijinal QuickDraw rutinleri (1980'lerden olanlar) noktaların sonsuz küçük olduğu matematiksel modeli kullandı. Ekrandaki noktalar pikseller arasında uzanır. Yani (3,5) 'den (10,5)' e çizilen bir çizgi 7 uzunluğunda ve 7 piksel işgal etti. Bugünün koordinatlarında bu çizginin uzunluğu 8 olurdu.
Barry Brown

@Barry: Bu çok mantıklı, çünkü XOR'u çok kullandığı için ve çizgileri birbirine bağlıyorsanız, buluştukları yerde eksik bir piksel olmadan bağlantı kurmasını istiyorsunuz. Aslında, her iki koordinat sistemini de göz önünde bulundurarak, çokgenleri doldurma hakkında bir imza kağıdı yayınladım.
Mike Dunlavey

0
Pa(x,y)*-----------------------------------*Pb(x,y)
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
Pc(x,y)*-----------------------------------*Pd(x,y)

Pb ve Pc'yi şu şekilde tanımlayabiliriz:

Pb (Pd (x), PA (y))

ve

PC (Pa (x), Pd (y))

Dolayısıyla simetri nedeniyle dört noktanın tümünü tanımlamaya gerek yoktur.

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.