Jaka jest idea definiowania prostokątów za pomocą dwóch punktów? [Zamknięte]

15

To nie jest tak, że to nie ma sensu, ale po prostu działa niezręcznie w 99% przypadków.

Często w grafice 2D prostokąty są inicjalizowane, przechowywane i przetwarzane jako para punktów. W żadnym konkretnym języku

class Rect:
   p1, p2: point

Bardziej sensowne jest zdefiniowanie prostokąta jako dwóch wartości x i dwóch wartości y, takich jak to:

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

Z dwoma punktami, jeśli w pewnym miejscu w kodzie źródłowym chcesz użyć wartości y dla góry, musisz powiedzieć rect.p1.y (hmmm, zatrzymaj się i pomyśl, czy to p1 czy p2), ale z czterema wartościami jako zwykłymi elementami danych, jest to jasne i bezpośrednie: rect.ytop (nie wymaga myślenia!) Użycie dwóch punktów oznacza, że ​​w przypadku pionu musisz splątać poziomo; istnieje zależność między niezależnymi elementami.

Jak powstał ten dwupunktowy pomysł i dlaczego się utrzymuje? Czy ma to jakąś zaletę w stosunku do samych współrzędnych xiy?

DODATKOWA UWAGA: To pytanie jest w kontekście wyrównanych prostokątów XY, takich jak menedżery okien i zestawy narzędzi GUI, a nie w kontekście dowolnych kształtów w aplikacji do rysowania i malowania.

DarenW
źródło
8
Czy napisałeś znaczną ilość kodu przy użyciu Rect?
6
Prostokąt jest zdefiniowany przez dwa punkty, więc przedstawienie ich jako dwóch punktów ma sens.
Adam Crossland,
2
Prostokąt jest bardziej naturalnie zdefiniowany jako zakres wartości x i zakres wartości y.
DarenW
2
Świetne pytanie! Sam nigdy o tym nie myślałem, ale robisz interesujący argument! FWIW, Windows ma również RECT, jak ty również opisujesz (górny, lewy, dolny, prawy)
Dean Harding
3
Jak zdefiniować prostokąt z dwoma punktami? Czy zakłada się, że nie ma rotacji?
Nick T

Odpowiedzi:

8

Czy uważasz, że jest mniej podatny na błędy?

Jeśli użyjesz (Point1, Point2), wtedy bardzo jasne jest, co określasz . Jeśli podasz 2 punkty, jedynym możliwym błędem jest to, że użytkownik pomieszał swoje xiy podczas konstruowania punktów, ponieważ kolejność punktów nie ma znaczenia.

Jeśli podasz 4 liczby całkowite, to jeśli ktoś nie zwraca uwagi, może podać (x1, x2, y1, y2), kiedy chcesz (x1, y1, x2, y2) lub odwrotnie. Ponadto niektóre interfejsy API, takie jak struktura Rect z WCF, definiują prostokąt jako (x, y, szerokość, wysokość), co może powodować zamieszanie w kwestii tego, co oznaczają (1, 2, 3, 4). Czy to (x, y, w, h) lub (x1, y1, x2, y2) lub (x1, x2, y1, y2)?

Podsumowując, (Punkt 1, Punkt 2) wydaje mi się nieco bezpieczniejszy.

MIA
źródło
3
Co powiesz na coś takiego jak Rect (xrange (x1, x2), yrange (y1, y2))? Wydaje się, że jest to najwyższy poziom bezpieczeństwa i elegancji użytkowania interfejsu API.
DarenW,
9

Zawsze lubiłem definiować prostokąt jako punkt + szerokość i wysokość, gdzie punkt jest lewym górnym rogiem prostokąta.

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

A następnie dodaj wszelkie potrzebne metody, aby pobrać inne metryki. Podobnie jak wersja Java

Martin Wickman
źródło
4
Czy górna y + wysokość, y-wysokość czy tylko y?
Cameron MacFarland,
2
@Cameron MacFarland: To zależy od układu współrzędnych aplikacji, który nie dotyczy mało prostokąta.
Jon Purdy,
2
@Martin Wickman: Jaka jest przewaga nad użyciem 2 punktów?
Kramii
@Kramii: Jedną z zalet jest to, że trzeba tłumaczyć tylko jeden punkt, jeśli przesuwasz cały prostokąt. Przy okazji, zawsze możesz obliczyć „brakujący punkt”, jeśli go potrzebujesz (wymiana procesora / pamięci).
Martin Wickman,
To też pojawia się w prawdziwym życiu. Uważam to za trudne, ponieważ jedną z najczęstszych rzeczy, które robię z prostokątami, jest sprawdzenie, czy zawiera się w nich punkt. Rysowanie jest również powszechne. W obu przypadkach konieczne jest dodanie, co przeszkadza licznikom taktowania tak jak ja.
DarenW,
7

W rzeczywistości prostokąt nie jest zdefiniowany przez 2 punkty. Prostokąt można zdefiniować tylko za pomocą dwóch punktów, jeśli jest równoległy do ​​osi.

Istnieje kilka sposobów reprezentowania prostokątów równoległych do osi:

  1. Dwa przeciwległe punkty po przekątnej
  2. Jeden punkt narożny, wysokość i szerokość
  3. Punkt środkowy, połowa wysokości i szerokość (niezbyt często, ale czasem przydatne).
  4. Jako dwie współrzędne X i dwie współrzędne Y.

W przypadku (1) wiele bibliotek używa konwencji, aby określić, które dwa punkty są używane - na przykład topLeft i bottomRight.

Wybór reprezentacji może wynikać z pierwotnego celu definicji prostokąta, ale wyobrażam sobie, że często jest to arbitralne . Reprezentacje są równoważne w informacjach, które niosą. Różnią się one jednak łatwością, z jaką można obliczyć właściwości prostokąta, oraz wygodą, z jaką operacje mogą być wykonywane na prostokącie.

Korzyści z definicji (1) w porównaniu do innych obejmują:

  • Spójność interfejsu API z innymi wielokątami, liniami itp.
  • topLeft, bottomRight można przekazać do dowolnej metody, która akceptuje punkty
  • Metody klasy Point można wywoływać na topLeft, bottomRight
  • Większość właściwości można łatwo uzyskać, np. bottomLeft, topRight, szerokość, wysokość, środek, długość po przekątnej itp.
Kramii
źródło
6

No cóż, p1: Pointczy p2: Pointkażda z nich będzie miała dwie intwspółrzędne , więc czy twoja klasa nie sprowadza się do tego samego?

A jeśli przechowujesz te dwa punkty jako obiekty pierwszej klasy Point, czy nie zyskujesz z nich trochę więcej użyteczności? W większości graficznych układów współrzędnych, które znam, punkty są podklasowane w ten sposób, aby stworzyć hierarchię obiektów point -> circle -> ellipsei tak dalej.

Jeśli więc tworzysz obiekt, który nie korzysta z Pointklasy, oddzieliłeś ten obiekt od reszty hierarchii klas.

Robert Harvey
źródło
1
Zaletą, jaką widzę w reprezentacji OP, jest to, że jeśli chcesz poznać niższą wartość y prostokąta, wiesz, że jest to „ybottom”, gdzie podobnie jak w przypadku p1 / p2 musisz dowiedzieć się, która z nich jest niższa. Jest tak, chyba że gwarantujesz, że p1 będzie niższą wartością.
Jason Viers
1
Chociaż prawdą jest, że obie różne struktury sprowadzają się do czterech współrzędnych, wersja z dwoma punktami wprowadza obcy poziom, który zbiera jeden x jeden y, bez szczególnego uzasadnienia, do którego x idzie z którym y. Nie widzę tego dodatkowego poziomu jako zapewniającego jakiekolwiek narzędzie po wielu latach programowania grafiki.
DarenW
1
@Jason: Dobra uwaga. Jednak dzięki podejściu ytop/ ybottom, musiałaby istnieć gwarancja gdzieś, co ybottomfaktycznie znajduje się poniżej ytop.
Dr Wily's Apprentice
Lub zadzwoń do nich y1 i y2 i użyj min (y1, y2) i max (y1, y2) - oczywiście byłoby to bardziej niezręczne nawet niż dostęp przez dwa punkty p1, p2.
DarenW,
nazewnictwo góra / dół nic ci nie kupuje, ponieważ nic nie zapobiega bottomx <topx, chyba że specjalnie dla tego kodujesz. Myślę, że spowodowałoby to zamieszanie.
lkg
5

Dlatego lubię Delphi TRect. Jest zdefiniowany jako rekord wariantowy (struktura ujednolicona w C-speak), który można interpretować jako punkt TopLeft i BottomRight lub liczby całkowite Top, Left, Bottom i Right, w zależności od tego, który z nich jest dogodniejszy.

Mason Wheeler
źródło
1
Tak, bardzo przydatna funkcja.
Orbling
4

Z pewnością jeśli zdefiniujesz prostokąt jako:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

wtedy od razu wiesz, który punkt jest który.

Jeszcze lepiej byłoby dodać dodatkowe właściwości, które pozwoliłyby ci manipulować prostokątem w dowolne sposoby potrzebne dla twojej aplikacji. Po prostu zaktualizują one podstawową strukturę danych.

Dodając transformację do kształtu, możesz ustawić prostokąt w dowolny sposób. Nadal będziesz potrzebować wyrównanego do osi obwiedni, aby szybko sprawdzić / odrzucić :)

Jeśli jednak Twój model dopuszcza prostokąty w dowolnej orientacji bez zastosowania transformacji, wówczas „dolny lewy” i „górny prawy” nie mają znaczenia, co prowadzi z powrotem do „p1” i „p2” (lub czegoś równoważnego).

ChrisF
źródło
Co się stanie, gdy obrócisz prostokąt o 90 stopni? Czy śledzisz teraz dwa różne punkty niż na początku, czy też „topRight” znajduje się teraz po lewej stronie „bottomLeft”?
Inaimathi
@Inaimathi - jeśli dodasz macierz transformacji, możesz utrzymać orientację prostokąta względem osi. Zależy to jednak od aplikacji.
ChrisF
2

myślę, że bardziej sensowne jest, aby prostokąt był reprezentowany przez zasięg xiy i punkt; możesz nawet ustawić punkt położenia na środku prostokąta, aby był niezależny od obrotu

ale prawdopodobnie najłatwiej było go zakodować jako dwa punkty!

Steven A. Lowe
źródło
Jak byłoby łatwiej zakodować jako dwa punkty?
DarenW,
@DaremW: typowe funkcje biblioteki rysowania prostokąta przyjmują za argumenty górny lewy i dolny prawy
Steven A. Lowe
Ale dlaczego te API są zaprojektowane w ten sposób? Poza tym bezmyślnie naśladuje wcześniejsze biblioteki.
DarenW,
@DarenW: zgaduję, że biblioteki używają procedury rysowania linii Bresenham, która przyjmuje dwa punkty jako dane wejściowe i jest bardzo wydajna
Steven A. Lowe
2

Nie podoba mi się to, ponieważ wyrzuciliśmy potencjalny stopień swobody, który zasadniczo pozwala na dowolną rotację. Ogólny prostokąt 2D ma pięć niewiadomych (stopnie swobody). Możemy określić je jako współrzędne punktu, długości dwóch boków, które tworzą wierzchołek z tym punktem, oraz kąt względem poziomu pierwszej linii (przy założeniu, że drugi ma kąt o 90 stopni większy). Można również zastosować nieskończoną liczbę innych możliwości, ale należy podać pięć niezależnych wielkości. Niektóre wybory doprowadzą do łatwiejszej algebry niż inne, w zależności od tego, co się z nimi zrobi.

Omega Centauri
źródło
5
Ważne jest, aby zdawać sobie sprawę, że „standardowa” struktura prostokąta nie jest rygorystycznie zdefiniowanym prostokątem matematycznym, ale uproszczoną wersją, która zawsze jest równoległa do osi X i Y, ponieważ została stworzona do użycia w jednym, bardzo konkretnym celu: zdefiniowaniu prostokątnych obszarów dla menedżera okien, które są (prawie) zawsze równoległe do osi X i Y.
Mason Wheeler,
+1, struktura lewy / prawy / górny / dolny jest wstępnie przypisana, a zatem ma mniej informacji
Javier
Dobra uwaga na temat wyrównanych prostokątów xy. Miałem na uwadze to, a także zakresy stosowane w modelowaniu 3D i kilka innych rzeczy, ale wszystkie xy (może również -z) są wyrównane.
DarenW,
1

Czy to nie to samo, co 2 punkty? Jak to jest niezręczne ... większość procedur rysowania wymaga punktów, a nie oddzielnych komponentów x / y.

Grandmaster B.
źródło
1

Definiowanie prostokątów jako par punktów pozwala ponownie wykorzystać punkt jako wierzchołek dla innego kształtu. Tylko myśl ...

RobotHumans
źródło
Wygląda jednak na grę z pół talią, aby zachować tylko dwa punkty, aby zdefiniować czterorożny kształt. Jeśli potrzebujesz górnego lewego, fajnego, ale jeśli potrzebujesz górnego prawego, musisz zrobić jakieś fantazyjne przechwytywanie danych.
DarenW
jeśli istnieje akcesorium, które jest zdefiniowane jako punkt AX punkt BY i punkt BX punkt AY, to czyni go lżejszym w pamięci / na dysku, myślę, że przechowuje o połowę mniej wierzchołków i po prostu wskazuje na nie (w zależności od maksymalnego rozmiaru siatki). Rozumiem, dokąd zmierzasz z zasięgiem, ale nie grasz z połową talii, po prostu nie przechowujesz duplikatów danych ... a inne kwestie, które należy wziąć pod uwagę, to jakie są ograniczenia pamięci? jakie są implikacje związane z ponowną implementacją przezbrojenie poprawek we wszystkich połączonych kodach.
RobotHumans
a ponieważ nie trzeba wykonywać żadnej „pracy”, aby usunąć dwa pierwsze wierzchołki z pamięci, prawdopodobnie jest to szybsze
RobotHumans
1

Uważam, że chodzi głównie o ustalenie jednorodności wszystkich prymitywów kształtu.

Jasne, że możesz zdefiniować prostokąt na wiele różnych sposobów, ale jak zdefiniować trójkąt, gwiazdę lub okrąg w sposób, który może wykorzystywać podobne struktury danych?

Wszystkie wielokąty można zdefiniować według ich punktów, z niewielką logiką, aby określić, co zrobić z punktami.

Biblioteki graficzne działają przede wszystkim na tych wielokątach pod względem wierzchołków i krawędzi, więc punkty i linie między nimi, wszystkie obliczenia działają na tych dwóch elementach, dobrze i na ściankach, ale to samo jest tylko funkcją krawędzi.

Orbling
źródło
1

W dwóch wymiarach zapisanie prostokąta jako dwóch punktów jest wyraźniejsze niż zdefiniowanie konkretnego narożnika oraz szerokości i wysokości - rozważ ujemną szerokość lub wysokość lub obliczenia wymagane do określenia każdej opcji z drugiej.

Wykonywanie obrotów na prostokącie zdefiniowanym przez punkty jest również znacznie prostsze niż zdefiniowane przez punkt plus szerokość i wysokość.

Spodziewałbym się, że enkapsulacja sprawi, że to zróżnicowanie nie będzie ważne jako użytkownik klasy.

Prostokąt powinien być zdefiniowany jako trzy punkty, które będą dobrze zdefiniowane w 3 wymiarach. Nie jestem całkowicie pewien wymogu definiowania prostokąta w 4 lub więcej wymiarach.

Armand
źródło
1

To jest całkowicie arbitralne. Potrzebujesz czterech informacji, aby narysować prostokąt. Projektanci bibliotek postanowili przedstawić go za pomocą dwóch punktów (każdy ze współrzędną xy), ale z łatwością mogliby to zrobić za pomocą x / y / w / h lub góra / dół / lewo / prawo.

Przypuszczam, że prawdziwym pytaniem PO jest: dlaczego dokonano tego konkretnego wyboru?

Barry Brown
źródło
1

Wybór parametrów jest ważny tylko dla projektantów / programistów niskiego poziomu.

Użytkownicy wysokiego poziomu muszą tylko pomyśleć o:

  • IsPointInRect
  • Powierzchnia
  • Przecięcie (lub przycięcie)
  • HasOverlap (to samo co Intersection.Area> 0)
  • Unia (staje się listą prostokątów)
  • Odejmowanie (lista prostokątów, które reprezentują ten sam zestaw punktów, który znajduje się w prostym A, ale nie w prostym B)
  • Przekształcać
    • Przesunięcia w X i Y
    • Obrót (0, 90, 180, 270)
    • Skalowanie w X i Y (patrz uwaga)
  • Prosta składnia dla właściwości Xmin, Xmax, Ymin, Ymax, Szerokość, Wysokość, dzięki czemu użytkownik nie musi znać dokładnego wyboru parametrów.

Uwaga: Aby zminimalizować utratę precyzji podczas skalowania transformacji, czasami właściwe jest zaimplementowanie drugiej klasy Rect, która używa współrzędnych zmiennoprzecinkowych, aby wyniki pośrednie mogły być dokładnie zapisane w sekwencji transformacji i zaokrąglone do liczby całkowitej w ostatni krok.

rwong
źródło
0

Jak mówi @Steven, myślę, że powinno być w kategoriach jednego (x, y) punktu i wektora wielkości (w, h). To dlatego, że łatwo wpaść w dwuznaczność. Załóżmy, że masz następujący wypełniony prostokąt zaczynający się w punkcie (0,0).

  012
0 XXX
1 XXX
2 XXX

Oczywiście jego szerokość, wysokość to (3,3), ale co to jest drugi punkt? Czy to (2,2) czy (3,3)?

Ta dwuznaczność może powodować różnego rodzaju problemy.

Dowiedziałem się w przykry sposób rok temu, że lepiej myśleć o współrzędnych graficznych jako linie między pikselami, nie jako linie piksele są na . W ten sposób nie ma dwuznaczności.

Mike Dunlavey
źródło
2
Oryginalne procedury QuickDraw na Macu (te z lat 80.) używały modelu matematycznego, w którym punkty były nieskończenie małe. Punkty na ekranie leżą między pikselami. Tak więc linia narysowana od (3,5) do (10,5) miała długość 7 i zajmowała 7 pikseli. W dzisiejszych współrzędnych linia ta miałaby długość 8.
Barry Brown
@Barry: To ma sens, ponieważ często używał XOR, a jeśli łączysz linie razem, chcesz, aby łączyły się bez brakującego piksela w miejscu, w którym się spotykają. Właściwie opublikowałem dokument siggraph na temat wypełniania wielokątów, biorąc pod uwagę oba układy współrzędnych.
Mike Dunlavey,
0
Pa(x,y)*-----------------------------------*Pb(x,y)
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
       |                                   |
Pc(x,y)*-----------------------------------*Pd(x,y)

Możemy zdefiniować zarówno Pb, jak i Pc w ten sposób:

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

i

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

Dlatego nie ma potrzeby definiowania wszystkich czterech punktów ze względu na symetrię

Ciemna noc
źródło