Apa ide di balik mendefinisikan persegi panjang dengan dua poin? [Tutup]

14

Bukannya ini tidak masuk akal, tetapi hanya berhasil 99% dari waktu canggung.

Seringkali dalam grafik 2D persegi panjang diinisialisasi, disimpan dan dimanipulasi sebagai sepasang titik. Dalam bahasa tertentu,

class Rect:
   p1, p2: point

Lebih masuk akal untuk mendefinisikan persegi panjang sebagai dua nilai x dan dua nilai y, seperti ini:

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

Dengan dua poin, jika di suatu tempat dalam kode sumber Anda ingin memanfaatkan nilai y dari atas, Anda harus mengatakan rect.p1.y (hmmm, berhenti dan pikirkan, apakah p1 atau p2) tetapi dengan empat nilai sebagai anggota data biasa, itu jelas dan langsung: rect.ytop (tidak perlu berpikir!) Penggunaan dua titik berarti bahwa dalam berurusan dengan vertikal, Anda harus kusut horizontal; ada hubungan yang asing antara unsur-unsur independen.

Bagaimana gagasan dua poin ini muncul dan mengapa itu bertahan? Apakah ada kelebihan dibandingkan koordinat bare x dan y?

CATATAN TAMBAHAN: Pertanyaan ini dalam konteks persegi panjang yang disejajarkan XY, seperti pada manajer jendela dan perangkat GUI, bukan dalam konteks bentuk sewenang-wenang dalam menggambar dan melukis aplikasi.

DarW
sumber
8
Sudahkah Anda menulis sejumlah besar kode menggunakan Rect?
6
Sebuah persegi panjang didefinisikan oleh dua titik, jadi mewakili mereka sebagai dua titik sangat masuk akal.
Adam Crossland
2
Sebuah persegi panjang lebih didefinisikan secara alami sebagai rentang nilai x dan rentang nilai y.
DarenW
2
Pertanyaan bagus! Saya tidak pernah memikirkannya sendiri, tetapi Anda membuat argumen yang menarik! FWIW, Windows memiliki RECT seperti yang Anda gambarkan juga (atas, kiri, bawah, kanan)
Dean Harding
3
Bagaimana Anda mendefinisikan sebuah persegi panjang dengan dua poin? Apakah diasumsikan tidak memiliki rotasi?
Nick T

Jawaban:

8

Sudahkah Anda menganggap itu lebih rentan kesalahan?

Jika Anda menggunakan (Point1, Point2) maka sangat jelas apa yang Anda tentukan. Jika Anda memberikan 2 poin, maka satu-satunya kesalahan yang mungkin adalah bahwa pengguna telah mencampur x dan y mereka ketika membangun poin karena urutan poin tidak masalah.

Jika Anda memberikan 4 bilangan bulat, maka jika seseorang tidak memperhatikan, mereka dapat memasok (x1, x2, y1, y2) ketika Anda inginkan (x1, y1, x2, y2) atau sebaliknya. Juga, beberapa API seperti struktur Rect WCF mendefinisikan persegi panjang sebagai (x, y, lebar, tinggi) yang kemudian dapat menyebabkan kebingungan tentang apa artinya (1, 2, 3, 4) artinya. Apakah itu (x, y, w, h) atau (x1, y1, x2, y2) atau (x1, x2, y1, y2)?

Secara keseluruhan, (Point1, Point2) tampaknya sedikit lebih aman bagi saya.

MIA
sumber
3
Bagaimana dengan sesuatu seperti Rect (xrange (x1, x2), yrange (y1, y2))? Itu tampaknya yang paling utama dalam keamanan dan keanggunan penggunaan API.
DarenW
9

Saya selalu suka mendefinisikan persegi panjang sebagai titik + lebar dan tinggi, di mana titik adalah sudut kiri atas persegi panjang.

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

Dan kemudian tambahkan metode apa pun yang Anda butuhkan untuk mengambil metrik lainnya. Seperti versi Java

Martin Wickman
sumber
4
Apakah puncak y + tinggi, y-tinggi atau hanya y?
Cameron MacFarland
2
@Cameron MacFarland: Itu tergantung pada sistem koordinat aplikasi, yang tidak peduli dengan persegi panjang rendah.
Jon Purdy
2
@ Martin Wickman: Apa keuntungan menggunakan 2 poin?
Kramii
@ Kramii: Salah satu keuntungannya adalah hanya perlu menerjemahkan satu poin jika Anda memindahkan seluruh kotak. Btw, Anda selalu dapat menghitung "titik hilang" jika Anda membutuhkannya (cpu / memory tradeoff).
Martin Wickman
Ini juga muncul dalam kehidupan nyata. Saya merasa rumit karena salah satu hal paling umum yang saya lakukan dengan persegi panjang adalah tes jika ada titik di dalamnya. Menggambar juga biasa. Dalam kedua kasus, penambahan perlu dilakukan, yang mengganggu counter siklus clock berkinerja tinggi seperti saya.
DarenW
7

Sebenarnya, seekor elang tidak ditentukan oleh 2 poin. Sebuah persegi panjang hanya dapat didefinisikan oleh dua titik jika sejajar dengan sumbu.

Ada beberapa cara untuk mewakili persegi panjang yang sejajar dengan sumbu:

  1. Dua titik berlawanan secara diagonal
  2. Satu titik sudut, tinggi dan lebar
  3. Titik tengah, setengah tinggi dan lebar (tidak umum, tetapi terkadang bermanfaat).
  4. Sebagai dua koordinat X dan dua koordinat Y

Untuk (1), banyak perpustakaan menggunakan konvensi untuk menentukan dua titik mana yang digunakan - topLeft dan bottomRight, misalnya.

Pilihan representasi mungkin didorong oleh tujuan asli dari definisi persegi panjang, tetapi saya membayangkan bahwa itu sering sewenang-wenang . Representasi tersebut setara dalam informasi yang dibawanya. Namun, mereka berbeda dalam kemudahan yang sifat-sifat persegi panjang dapat dihitung dan kenyamanan yang dengannya operasi dapat dilakukan pada reektangle.

Manfaat definisi (1) dibandingkan yang lain meliputi:

  • Konsistensi API dengan poligon, garis, dll.
  • topLeft, bottomRight dapat dikirimkan ke metode apa pun yang menerima poin
  • Metode kelas Point dapat dipanggil pada topLeft, bottomRight
  • Sebagian besar properti dapat diturunkan dengan mudah, misalnya. bottomLeft, topRight, lebar, tinggi, tengah, panjang diagonal, dll.
Kramii
sumber
6

Nah p1: Pointdan p2: Pointmasing-masing akan memiliki dua intkoordinat di dalamnya, jadi bukankah kelas Anda sama dengan hal yang sama?

Dan jika Anda menyimpan kedua titik itu sebagai Pointobjek kelas satu , tidakkah Anda mendapat sedikit lebih banyak utilitas dari mereka? Dalam sebagian besar sistem koordinat grafis yang saya ketahui, poin disubklasifikasikan dengan cara ini untuk membuat hierarki objek: point -> circle -> ellipsedan seterusnya.

Jadi jika Anda membuat objek yang tidak menggunakan Pointkelas, Anda telah menceraikan objek itu dari sisa hierarki kelas.

Robert Harvey
sumber
1
Keuntungan yang saya lihat dari representasi OP adalah jika Anda ingin mengetahui nilai y yang lebih rendah dari sebuah persegi panjang, Anda tahu itu "ybottom", sedangkan dengan p1 / p2 Anda perlu mencari tahu mana yang lebih rendah. Ini kecuali Anda menjamin p1 akan menjadi nilai yang lebih rendah.
Jason Viers
1
Meskipun memang benar kedua struct yang berbeda bermuara pada empat koordinat, versi dua poin memperkenalkan level asing yang mengumpulkan satu x dan satu y, tanpa dasar pemikiran tertentu yang digunakan x untuk y. Saya tidak melihat level ekstra ini menyediakan utilitas apa pun, setelah bertahun-tahun pemrograman grafis.
DarenW
1
@Jason: Poin bagus. Namun, dengan pendekatan ytop/ ybottom, perlu ada jaminan di suatu tempat yang ybottomsebenarnya di bawah ini ytop.
Apprentice Dr. Wily
Atau panggil mereka em y1 dan y2, dan gunakan min (y1, y2) dan maks (y1, y2) - tentu saja itu akan lebih clumsier bahkan dari akses melalui dua poin p1, p2.
DarenW
penamaan top / bottom tidak memberi Anda apa-apa karena tidak ada yang mencegah bottomx <topx, kecuali jika Anda membuat kode khusus untuk itu. Saya pikir itu hanya akan menambah kebingungan.
lkg
5

Ini sebabnya saya suka Delphi TRect. Ini didefinisikan sebagai rekaman varian (struct serikat dalam bahasa-C) yang dapat diartikan sebagai TopLeft dan titik BottomRight, atau bilangan bulat Atas, Kiri, Bawah dan Kanan, mana yang lebih nyaman saat ini.

Mason Wheeler
sumber
1
Ya, fitur yang sangat berguna itu.
Orbling
4

Tentunya jika Anda mendefinisikan persegi panjang Anda sebagai:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

maka Anda langsung tahu titik mana yang mana.

Yang lebih baik adalah menambahkan properti tambahan yang memungkinkan Anda untuk memanipulasi persegi panjang di mana cara yang Anda butuhkan untuk aplikasi Anda. Ini hanya akan memperbarui struktur data yang mendasarinya.

Dengan menambahkan transformasi ke bentuk, Anda bisa mengarahkan persegi panjang Anda dengan cara apa pun yang Anda inginkan. Anda masih membutuhkan kotak pembatas yang disejajarkan dengan sumbu untuk menerima cepat / menolak cek :)

Namun, jika model Anda memungkinkan persegi panjang dalam orientasi apa pun tanpa menerapkan transformasi maka "kiri bawah" dan "kanan atas" tidak memiliki makna, yang mengarah kembali ke "p1" dan "p2" (atau sesuatu yang setara).

ChrisF
sumber
Jadi apa yang terjadi ketika Anda memutar persegi panjang sebesar 90 derajat? Apakah Anda sekarang melacak dua titik berbeda dari pada awalnya, atau apakah "hak atas" Anda sekarang di sebelah kiri "bottomLeft"?
Inaimathi
@Inaimathi - jika Anda menambahkan matriks transformasi, Anda dapat menjaga persegi panjang tetap berorientasi dengan sumbu. Namun, itu tergantung pada aplikasi Anda.
ChrisF
2

saya pikir lebih masuk akal untuk sebuah persegi panjang untuk diwakili oleh x dan y sejauh dan titik; Anda bahkan dapat membuat titik lokasi pusat persegi panjang sehingga tidak tergantung pada rotasi

tapi itu mungkin paling mudah untuk mengkodekannya sebagai dua poin!

Steven A. Lowe
sumber
Bagaimana kode menjadi dua poin lebih mudah?
DarenW
@DaremW: fungsi perpustakaan menggambar-persegi panjang khas mengambil poin kiri atas dan kanan bawah sebagai argumen
Steven A. Lowe
Tapi mengapa API itu dirancang seperti itu? Selain meniru perpustakaan sebelumnya, yaitu.
DarenW
@ DarenW: dugaan saya adalah bahwa perpustakaan menggunakan rutinitas menggambar garis Bresenham, yang mengambil dua poin sebagai input dan sangat efisien
Steven A. Lowe
2

Saya tidak suka karena kami telah membuang tingkat kebebasan potensial, yang pada dasarnya memungkinkan untuk rotasi sewenang-wenang. Persegi panjang 2D umum memiliki lima yang tidak diketahui (derajat kebebasan). Kita dapat menetapkannya sebagai koordinat titik, panjang kedua sisi yang membentuk titik dengan titik ini, dan sudut dari garis horizontal garis pertama (yang lain diasumsikan memiliki sudut 90 derajat lebih besar). Jumlah tak terbatas dari kemungkinan lain juga dapat digunakan, tetapi ada lima jumlah independen yang harus ditentukan. Beberapa pilihan akan mengarah ke aljabar yang lebih mudah daripada yang lain, tergantung pada apa yang dilakukan dengannya.

Omega Centauri
sumber
5
Sangat penting untuk menyadari bahwa struktur persegi panjang "standar" bukan persegi panjang matematika yang terdefinisi dengan ketat, tetapi versi yang disederhanakan yang selalu sejajar dengan sumbu X dan Y, karena itu dibuat untuk digunakan untuk satu hal yang sangat spesifik: mendefinisikan daerah persegi panjang untuk window manager, yang (hampir) selalu sejajar dengan sumbu X dan Y.
Mason Wheeler
+1, struktur kiri / kanan / atas / bawah diseleksi, dan oleh karena itu memiliki informasi yang lebih sedikit
Javier
Poin bagus, tentang persegi panjang yang disejajarkan xy. Saya ada dalam pikiran itu, dan juga luasan seperti yang digunakan dalam pemodelan 3D, dan beberapa hal lain, tetapi semua xy (mungkin juga -z) selaras.
DarenW
1

Bukankah itu persis sama dengan 2 poin? Bagaimana ini canggung ... sebagian besar rutinitas menggambar memerlukan poin, bukan komponen x / y yang terpisah.

GrandmasterB
sumber
1

Mendefinisikan persegi panjang sebagai pasangan titik memungkinkan Anda menggunakan kembali titik tersebut sebagai simpul untuk bentuk lain. Hanya pemikiran saja...

RobotHumans
sumber
Tapi sepertinya bermain dengan setengah geladak, untuk mempertahankan hanya dua poin untuk menentukan bentuk empat sudut. Jika Anda membutuhkan kiri atas, keren, tetapi jika Anda perlu kanan atas, Anda harus melakukan pengambilan data mewah, secara relatif.
DarenW
jika ada accessor yang didefinisikan sebagai titik AX titik BY dan titik BX ​​titik AY itu membuatnya lebih ringan di memori / pada disk saya pikir untuk menyimpan setengah banyak vertex dan hanya menunjuk mereka (tergantung pada ukuran kotak maksimum). Saya sampai di mana Anda akan pergi dengan rentang pikiran Anda, tetapi Anda tidak bermain dengan setengah geladak, Anda hanya tidak menyimpan data duplikat .... dan poin lain yang harus dibuat adalah apa kendala memori? apa implikasi implementasi ulang memperlengkapi rect di semua kode yang saling berhubungan.
RobotHumans
dan karena Anda tidak perlu melakukan "pekerjaan" apa pun untuk mendapatkan dua simpul pertama dari memori, mungkin lebih cepat
RobotHumans
1

Saya percaya ini terutama untuk membangun keseragaman antara semua bentuk primitif.

Tentu Anda bisa mendefinisikan persegi panjang dengan banyak cara berbeda, tetapi bagaimana Anda mendefinisikan segitiga, atau bintang, atau lingkaran dengan cara yang dapat menggunakan struktur data serupa?

Semua poligon dapat didefinisikan oleh poin-poinnya, dengan logika singkat untuk menentukan apa yang harus dilakukan dengan poin-poin tersebut.

Pustaka grafis terutama beroperasi pada poligon ini dalam hal simpul dan tepi, sehingga titik dan garis di antara mereka, semua perhitungan bekerja pada dua fitur ini, baik itu dan sisi, tetapi itu sendiri hanyalah fungsi dari tepi.

Orbling
sumber
1

Dalam dua dimensi, menyimpan persegi panjang sebagai dua titik lebih jelas daripada mendefinisikan sudut tertentu dan lebar dan tinggi - pertimbangkan lebar atau tinggi negatif, atau perhitungan yang diperlukan untuk menentukan setiap opsi dari yang lain.

Melakukan rotasi pada persegi panjang yang ditentukan oleh titik juga jauh lebih sederhana daripada yang didefinisikan dengan titik plus lebar dan tinggi.

Saya berharap enkapsulasi membuat diferensiasi ini tidak penting sebagai pengguna kelas.

Sebuah persegi panjang harus didefinisikan sebagai tiga titik yang harus didefinisikan dengan baik dalam 3 dimensi. Saya tidak sepenuhnya yakin tentang persyaratan untuk mendefinisikan sebuah persegi panjang dalam 4 atau lebih dimensi.

Armand
sumber
1

Ini sepenuhnya sewenang-wenang. Anda memerlukan empat bagian informasi untuk menggambar persegi panjang. Perancang perpustakaan memutuskan untuk mewakilinya dengan dua poin (masing-masing dengan koordinat xy), tetapi bisa dengan mudah melakukannya dengan x / y / w / h atau atas / bawah / kiri / kanan.

Saya kira pertanyaan sebenarnya OP adalah: mengapa pilihan khusus ini dibuat?

Barry Brown
sumber
1

Pilihan parameter hanya penting bagi desainer / coders tingkat rendah.

Pengguna tingkat tinggi hanya perlu memikirkan:

  • IsPointInRect
  • Daerah
  • Persimpangan (atau Kliping)
  • HasOverlap (sama dengan Intersection.Area> 0)
  • Union (menjadi daftar persegi panjang)
  • Subtraction (daftar persegi panjang yang mewakili set titik yang sama yaitu di rect A tetapi tidak di rect B)
  • Mengubah
    • Bergeser dalam X dan Y
    • Rotasi (0, 90, 180, 270)
    • Penskalaan dalam X dan Y (lihat catatan)
  • Sintaks sederhana untuk properti Xmin, Xmax, Ymin, Ymax, Width, Height sehingga pengguna tidak perlu mengetahui pilihan parameter yang tepat.

Catatan: Untuk meminimalkan kehilangan presisi selama transformasi penskalaan, kadang-kadang tepat untuk menerapkan kelas Rect kedua yang menggunakan koordinat titik-mengambang, sehingga hasil antara dapat disimpan secara akurat dalam urutan transformasi dan hanya dibulatkan ke bilangan bulat di langkah terakhir.

rwong
sumber
0

Seperti @teven mengatakan, saya pikir itu harus dalam hal satu (x, y) titik, dan vektor ukuran (w, h). Itu karena mudah jatuh ke dalam ambiguitas. Misalkan Anda memiliki persegi panjang terisi berikut mulai dari titik (0,0).

  012
0 XXX
1 XXX
2 XXX

Jelas itu lebar, tinggi adalah (3,3), tapi apa itu poin kedua? Apakah (2,2) atau (3,3)?

Ambiguitas ini dapat menyebabkan semua jenis masalah.

Saya belajar dengan cara yang keras tahun yang lalu bahwa lebih baik untuk memikirkan koordinat grafis sebagai garis antara piksel, bukan sebagai garis piksel yang di . Dengan begitu tidak ada ambiguitas.

Mike Dunlavey
sumber
2
Rutin QuickDraw asli pada Mac (yang dari tahun 1980-an) menggunakan model matematika yang poinnya sangat kecil. Titik-titik di layar terletak di antara piksel. Jadi garis yang ditarik dari (3,5) ke (10,5) memiliki panjang 7 dan ditempati 7 piksel. Dalam koordinat hari ini, garis itu akan memiliki panjang 8.
Barry Brown
@ Larry: Itu masuk akal, karena XOR banyak digunakan, dan jika Anda merangkai garis-garis, Anda ingin mereka terhubung tanpa pixel yang hilang di mana mereka bertemu. Saya sebenarnya menerbitkan kertas siggraph untuk mengisi poligon, mengingat kedua sistem koordinat.
Mike Dunlavey
0
Pa(x,y)*-----------------------------------*Pb(x,y)
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
Pc(x,y)*-----------------------------------*Pd(x,y)

Kita dapat mendefinisikan kedua Pb & Pc dengan demikian:

Pb (Pd (x), Pa (y))

dan

Pc (Pa (x), Pd (y))

Jadi tidak perlu mendefinisikan keempat poin karena simetri

Malam gelap
sumber