Ý tưởng đằng sau việc xác định hình chữ nhật có hai điểm là gì? [đóng cửa]


14

Không phải là điều này không có ý nghĩa, nhưng nó chỉ giải quyết được 99% vụng về.

Thông thường trong các hình chữ nhật đồ họa 2D được khởi tạo, lưu trữ và thao tác như một cặp điểm. Không có ngôn ngữ cụ thể,

class Rect:
   p1, p2: point

Sẽ có ý nghĩa hơn khi định nghĩa một hình chữ nhật là hai giá trị x và hai giá trị y, như thế này:

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

Với hai điểm, nếu tại một vị trí nào đó trong mã nguồn bạn muốn sử dụng giá trị y của đỉnh, bạn phải nói orth.p1.y (hmmm, dừng lại và suy nghĩ, đó là p1 hoặc p2) nhưng với bốn giá trị là thành viên dữ liệu đơn giản, rõ ràng và trực tiếp: orth.ytop (không cần suy nghĩ!) Việc sử dụng hai điểm có nghĩa là trong việc xử lý theo chiều dọc, bạn phải rối theo chiều ngang; có một mối quan hệ ngoại lai giữa các yếu tố độc lập.

Làm thế nào mà ý tưởng hai điểm này xuất hiện và tại sao nó vẫn tồn tại? Liệu nó có một số lợi ích so với tọa độ trần x và y?

THÊM LƯU Ý: Câu hỏi này nằm trong ngữ cảnh của các hình chữ nhật được căn chỉnh XY, chẳng hạn như trong trình quản lý cửa sổ và bộ công cụ GUI, không phải trong bối cảnh các hình dạng tùy ý trong ứng dụng vẽ và vẽ.


8
Bạn đã viết một số lượng đáng kể mã bằng Rects chưa?

6
Một hình chữ nhật được xác định bởi hai điểm, do đó, đại diện cho chúng là hai điểm có rất nhiều ý nghĩa.
Adam Crossland

2
Một hình chữ nhật được định nghĩa tự nhiên hơn là một phạm vi các giá trị x và một phạm vi các giá trị y.
DarenW

2
Câu hỏi tuyệt vời! Tôi chưa bao giờ nghĩ về nó, nhưng bạn đưa ra một lập luận thú vị! FWIW, Windows cũng có RECT giống như bạn mô tả (trên cùng, bên trái, dưới cùng, bên phải)
Dean Harding

3
Làm thế nào để bạn xác định một hình chữ nhật với hai điểm? Được cho là không có vòng quay?
Nick T

Câu trả lời:


8

Bạn có nghĩ rằng nó ít bị lỗi hơn?

Nếu bạn sử dụng (Point1, Point2) nó sau đó được rất rõ ràng những gì bạn đang xác định. Nếu bạn cung cấp 2 điểm, thì lỗi duy nhất có thể xảy ra là người dùng đã trộn lẫn x và y của họ khi xây dựng các điểm là thứ tự của các điểm không thành vấn đề.

Nếu bạn cung cấp 4 số nguyên, thì nếu ai đó không chú ý, họ có thể cung cấp (x1, x2, y1, y2) khi bạn muốn (x1, y1, x2, y2) hoặc ngược lại. Ngoài ra, một số API như cấu trúc Rect của WCF xác định một hình chữ nhật là (x, y, chiều rộng, chiều cao) sau đó có thể gây nhầm lẫn về ý nghĩa của (1, 2, 3, 4). Đó là (x, y, w, h) hay (x1, y1, x2, y2) hay (x1, x2, y1, y2)?

Nói chung, (Point1, Point2) có vẻ an toàn hơn một chút đối với tôi.


3
Còn những thứ như Rect (xrange (x1, x2), yrange (y1, y2)) thì sao? Điều đó có vẻ là tối thượng trong an toàn và thanh lịch sử dụng API.
DarenW

9

Tôi luôn thích xác định một hình chữ nhật là một điểm + chiều rộng và chiều cao, trong đó điểm là góc trên bên trái của hình chữ nhật.

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

Và sau đó thêm bất kỳ phương pháp nào bạn cần để tìm nạp các số liệu khác. Giống như phiên bản Java


4
Là đỉnh y + chiều cao, chiều cao y hay chỉ y?
Cameron MacFarland

2
@Cameron MacFarland: Điều đó phụ thuộc vào hệ tọa độ của ứng dụng, không liên quan đến hình chữ nhật thấp.
Jon Purdy

2
@Martin Wickman: lợi thế của việc sử dụng 2 điểm là gì?
Kramii

@Kramii: Một lợi thế là chỉ phải dịch một điểm nếu bạn đang di chuyển toàn bộ trực tràng. Btw, bạn luôn có thể tính toán "điểm thiếu" nếu bạn cần nó (trao đổi cpu / bộ nhớ).
Martin Wickman

Điều này cũng xuất hiện trong cuộc sống thực. Tôi thấy nó khó khăn vì một trong những điều phổ biến nhất tôi làm với hình chữ nhật là kiểm tra nếu một điểm được chứa trong đó. Vẽ cũng là phổ biến. Trong cả hai trường hợp, việc bổ sung cần phải được thực hiện, điều này làm phiền các bộ đếm chu kỳ đồng hồ hiệu suất cao như tôi.
DarenW

7

Trên thực tế, một trực tràng không được xác định bởi 2 điểm. Một hình chữ nhật chỉ có thể được xác định bởi hai điểm nếu nó song song với các trục.

Có một số cách để biểu diễn các hình chữ nhật song song với các trục:

  1. Hai điểm chéo nhau
  2. Một góc, chiều cao và chiều rộng
  3. Điểm trung tâm, một nửa chiều cao và chiều rộng (không phổ biến, nhưng đôi khi hữu ích).
  4. Là hai tọa độ X và hai tọa độ Y

Đối với (1), nhiều thư viện sử dụng quy ước để xác định hai điểm nào được sử dụng - ví dụ: topLeft và bottomRight.

Sự lựa chọn đại diện có thể được điều khiển bởi mục đích ban đầu của định nghĩa hình chữ nhật, nhưng tôi tưởng tượng rằng nó thường tùy ý . Các đại diện là tương đương trong thông tin mà họ mang theo. Tuy nhiên, chúng khác nhau ở chỗ dễ tính toán các thuộc tính của hình chữ nhật và sự thuận tiện với các thao tác có thể được thực hiện trên hình chữ nhật lại.

Lợi ích của định nghĩa (1) so với những người khác bao gồm:

  • Tính nhất quán của API với các đa giác, dòng khác, v.v.
  • topLeft, bottomRight có thể được truyền cho bất kỳ phương thức nào chấp nhận điểm
  • Các phương thức của lớp Point có thể được gọi trên topLeft, bottomRight
  • Hầu hết các thuộc tính có thể được bắt nguồn dễ dàng, ví dụ. bottomLeft, topRight, chiều rộng, chiều cao, trung tâm, chiều dài đường chéo, v.v.

6

Chà p1: Pointvà dù sao thì p2: Pointmỗi người sẽ có hai inttọa độ trong đó, vậy lớp học của bạn có giống nhau không?

Và nếu bạn lưu trữ hai điểm đó dưới dạng Pointcác đối tượng hạng nhất , bạn không nhận được thêm một chút tiện ích từ chúng? Trong hầu hết các hệ tọa độ đồ họa mà tôi biết, các điểm được phân lớp theo cách này để tạo cấu trúc phân cấp của các đối tượng: point -> circle -> ellipsev.v.

Vì vậy, nếu bạn tạo một đối tượng không sử dụng Pointlớp, bạn đã tách đối tượng đó khỏi phần còn lại của hệ thống phân cấp lớp.


1
Lợi thế tôi thấy về đại diện của OP là nếu bạn muốn biết giá trị y thấp hơn của hình chữ nhật, bạn biết đó là "ybottom", trong đó với p1 / p2, bạn cần tìm ra giá trị nào thấp hơn. Điều này là trừ khi bạn đảm bảo p1 sẽ là giá trị thấp hơn.
Jason Viers

1
Mặc dù đúng là hai cấu trúc khác nhau đều có tới bốn tọa độ, phiên bản hai điểm giới thiệu một mức độ ngoại lai tập hợp một x và một y, không có lý do cụ thể nào x đi với y. Tôi không thấy cấp độ bổ sung này là cung cấp bất kỳ tiện ích nào, sau nhiều năm lập trình đồ họa.
DarenW

1
@Jason: Điểm tốt. Với sự ytop/ ybottomcách tiếp cận, tuy nhiên, có thể cũng cần phải là một đâu đó bảo đảm rằng ybottomthực sự là bên dưới ytop.
Học viên của Tiến sĩ Wily

Hoặc gọi 'em y1 và y2, và sử dụng min (y1, y2) và max (y1, y2) - tất nhiên điều đó sẽ vụng về hơn ngay cả khi truy cập qua hai điểm p1, p2.
DarenW

việc đặt tên trên cùng / dưới cùng mua cho bạn không có gì vì không có gì ngăn cản bottomx <topx, trừ khi bạn mã hóa cụ thể. Tôi nghĩ rằng nó sẽ chỉ thêm sự nhầm lẫn.
lkg

5

Đây là lý do tại sao tôi thích Delphi's TRect. Nó được định nghĩa là một bản ghi biến thể (union struct in C-speak) có thể được hiểu là một điểm TopLeft và bottomRight hoặc các số nguyên Top, Left, bottom và Right, bất cứ lúc nào thuận tiện hơn.


1
Aye, tính năng rất hữu ích đó.
Orble

4

Chắc chắn nếu bạn xác định hình chữ nhật của bạn là:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

sau đó bạn biết ngay điểm nào là điểm nào.

Thậm chí tốt hơn là thêm các thuộc tính bổ sung cho phép bạn thao tác với hình chữ nhật theo cách bạn cần cho ứng dụng của mình. Chúng chỉ đơn giản là cập nhật cấu trúc dữ liệu cơ bản.

Bằng cách thêm một biến đổi cho hình dạng, bạn có thể định hướng hình chữ nhật của mình theo bất kỳ cách nào bạn muốn. Bạn vẫn cần một hộp giới hạn căn chỉnh trục để kiểm tra chấp nhận / từ chối nhanh chóng :)

Tuy nhiên, nếu mô hình của bạn cho phép hình chữ nhật theo bất kỳ hướng nào mà không áp dụng chuyển đổi thì "dưới cùng bên trái" và "trên cùng bên phải" không có nghĩa, dẫn đến "p1" và "p2" (hoặc một cái gì đó tương đương).


Vậy điều gì xảy ra khi bạn xoay hình chữ nhật 90 độ? Bây giờ bạn có đang theo dõi hai điểm khác nhau so với ban đầu hay là "topRight" của bạn bây giờ ở bên trái của "bottomLeft"?
Inaimathi

@Inaimathi - nếu bạn thêm ma trận biến đổi, bạn có thể giữ hình chữ nhật được định hướng theo trục. Tuy nhiên, nó phụ thuộc vào ứng dụng của bạn.
ChrisF

2

tôi nghĩ rằng nó có ý nghĩa hơn cho một hình chữ nhật được đại diện bởi một phạm vi x và y và một điểm; bạn thậm chí có thể đặt vị trí chỉ vào tâm của hình chữ nhật để nó không phụ thuộc vào xoay

nhưng có lẽ dễ nhất để mã nó thành hai điểm!


Làm thế nào nó sẽ dễ dàng hơn để mã như hai điểm?
DarenW

@DaremW: các hàm thư viện hình chữ nhật điển hình lấy các điểm trên bên trái và bên phải phía dưới làm đối số
Steven A. Lowe

Nhưng tại sao các API đó được thiết kế theo cách đó? Bên cạnh vô thức bắt chước các thư viện trước đó, đó là.
DarenW

@DarenW: tôi đoán rằng các thư viện sẽ sử dụng thói quen vẽ đường thẳng Bresenham, lấy hai điểm làm đầu vào và rất hiệu quả
Steven A. Lowe

2

Tôi không thích nó bởi vì chúng tôi đã đưa ra một mức độ tự do tiềm năng, về cơ bản cho phép xoay vòng tùy ý. Một hình chữ nhật 2D chung có năm ẩn số (bậc tự do). Chúng ta có thể chỉ định chúng là tọa độ của một điểm, độ dài của hai cạnh tạo thành một đỉnh với điểm này và góc từ phương ngang của đường thẳng thứ nhất (góc kia được cho là có góc lớn hơn 90 độ). Một số lượng vô hạn các khả năng khác cũng có thể được sử dụng, nhưng có năm đại lượng độc lập phải được chỉ định. Một số lựa chọn sẽ dẫn đến đại số dễ dàng hơn những lựa chọn khác, tùy thuộc vào những gì được thực hiện với chúng.


5
Điều quan trọng cần nhận ra là cấu trúc hình chữ nhật "tiêu chuẩn" không phải là hình chữ nhật toán học được xác định nghiêm ngặt, mà là một phiên bản đơn giản luôn song song với trục X và Y, bởi vì nó được tạo ra để sử dụng cho một điều rất cụ thể: xác định vùng hình chữ nhật đối với trình quản lý cửa sổ, gần như luôn luôn song song với trục X và Y.
Mason Wheeler

+1, cấu trúc trái / phải / trên / dưới được đặt trước và do đó có ít thông tin hơn
Javier

Điểm tốt, về xy hình chữ nhật thẳng hàng. Tôi đã nghĩ rằng, và cũng mở rộng như được sử dụng trong mô hình 3D và một số thứ khác, nhưng tất cả xy (cũng có thể là -z) được căn chỉnh.
DarenW

1

Không phải đó chính xác là 2 điểm sao? Làm thế nào là khó xử này ... hầu hết các thói quen vẽ yêu cầu điểm, không tách các thành phần x / y.


1

Xác định hình chữ nhật là cặp điểm cho phép bạn sử dụng lại điểm làm đỉnh cho hình dạng khác. Chỉ là một suy nghĩ ...


Nhưng có vẻ như chơi với một nửa bộ bài, chỉ giữ hai điểm để xác định hình dạng bốn góc. Nếu bạn tình cờ cần phía trên bên trái, mát mẻ, nhưng nếu bạn cần phía trên bên phải, bạn phải thực hiện một số thao tác lấy dữ liệu ưa thích, nói một cách tương đối.
DarenW

nếu có một bộ truy cập được xác định là điểm AX điểm BY và điểm BX điểm AY thì nó làm cho nó nhẹ hơn trong bộ nhớ / trên đĩa, tôi nghĩ rằng sẽ lưu trữ một nửa số đỉnh và chỉ vào chúng (tùy thuộc vào kích thước lưới tối đa). Tôi đến nơi bạn đang đi với suy nghĩ phạm vi của mình, nhưng bạn không chơi với một nửa bộ bài, bạn chỉ không lưu trữ dữ liệu trùng lặp .... và các điểm khác được thực hiện là những hạn chế về bộ nhớ là gì? các hàm ý thực hiện lại là gì trong tất cả các mã được liên kết với nhau.
RobotHumans

và vì bạn không phải thực hiện bất kỳ "công việc" nào để lấy hai đỉnh đầu tiên ra khỏi bộ nhớ, nên nó có thể nhanh hơn
RobotHumans

1

Tôi tin rằng nó chủ yếu là để thiết lập sự đồng nhất giữa tất cả các nguyên thủy hình dạng.

Chắc chắn bạn có thể định nghĩa hình chữ nhật theo nhiều cách khác nhau, nhưng làm thế nào để bạn xác định một hình tam giác, hoặc một ngôi sao hoặc một hình tròn theo cách có thể sử dụng các cấu trúc dữ liệu tương tự?

Tất cả các đa giác có thể được xác định bởi các điểm của chúng, với một lượng logic ngắn để xác định phải làm gì với các điểm.

Các thư viện đồ họa chủ yếu hoạt động trên các đa giác này theo các đỉnh và cạnh, vì vậy các điểm và các đường giữa chúng, tất cả các phép tính hoạt động trên hai tính năng này, cũng như các khía cạnh, nhưng bản thân nó chỉ là một chức năng của các cạnh.


1

Trong hai chiều, lưu trữ một hình chữ nhật là hai điểm rõ ràng hơn so với việc xác định một góc cụ thể và chiều rộng và chiều cao - xem xét chiều rộng hoặc chiều cao âm hoặc các phép tính cần thiết để xác định từng tùy chọn khác.

Thực hiện các phép quay trên một hình chữ nhật được xác định bởi các điểm cũng đơn giản hơn nhiều so với một điểm được xác định bằng một điểm cộng với chiều rộng và chiều cao.

Tôi hy vọng việc đóng gói sẽ làm cho sự khác biệt này không quan trọng với tư cách là người dùng của lớp.

Một hình chữ nhật nên được xác định là ba điểm sẽ được xác định rõ trong 3 chiều. Tôi không hoàn toàn chắc chắn về yêu cầu xác định hình chữ nhật có 4 chiều trở lên.


1

Nó hoàn toàn tùy ý. Bạn cần bốn mẩu thông tin để vẽ một hình chữ nhật. Nhà thiết kế thư viện đã quyết định đại diện cho nó bằng hai điểm (mỗi điểm có tọa độ xy), nhưng có thể dễ dàng thực hiện điều đó với x / y / w / h hoặc trên / dưới / trái / phải.

Tôi cho rằng câu hỏi thực sự của OP là: tại sao sự lựa chọn đặc biệt này được đưa ra?


1

Việc lựa chọn các tham số chỉ quan trọng đối với các nhà thiết kế / lập trình viên cấp thấp.

Người dùng cấp cao chỉ cần suy nghĩ về:

  • IsPointInRect
  • Khu vực
  • Giao lộ (hoặc cắt)
  • HasOverlap (giống như Giao lộ.Area> 0)
  • Liên minh (trở thành một danh sách các hình chữ nhật)
  • Phép trừ (danh sách các hình chữ nhật đại diện cho cùng một tập hợp điểm nằm trong trực tràng A nhưng không phải trong trực tràng B)
  • Biến đổi
    • Sự thay đổi trong X và Y
    • Xoay (0, 90, 180, 270)
    • Chia tỷ lệ theo X và Y (xem ghi chú)
  • Cú pháp đơn giản cho các thuộc tính Xmin, Xmax, Ymin, Ymax, Width, height để người dùng không cần biết chính xác lựa chọn tham số.

Lưu ý: Để giảm thiểu mất độ chính xác trong quá trình biến đổi tỷ lệ, đôi khi nên thực hiện lớp Rect thứ hai sử dụng tọa độ dấu phẩy động, để các kết quả trung gian có thể được lưu trữ chính xác trong một chuỗi các biến đổi và chỉ được làm tròn thành số nguyên trong Bước cuối cùng.


0

Như @Steven nói, tôi nghĩ rằng nó nên theo một điểm (x, y) và một vectơ kích thước (w, h). Đó là bởi vì nó dễ rơi vào một sự mơ hồ. Giả sử bạn có hình chữ nhật điền vào sau bắt đầu từ điểm (0,0).

  012
0 XXX
1 XXX
2 XXX

Rõ ràng đó là chiều rộng, chiều cao là (3,3), nhưng điểm thứ hai là gì? Là (2,2) hay (3,3)?

Sự mơ hồ này có thể gây ra tất cả các loại vấn đề.

Tôi đã học được một cách khó khăn từ nhiều năm trước rằng tốt hơn nên nghĩ về tọa độ đồ họa là các đường giữa các pixel, chứ không phải là các dòng pixel đang bật . Theo cách đó, không có sự mơ hồ.


2
Các thói quen QuickDraw ban đầu trên Mac (những người từ những năm 1980) đã sử dụng mô hình toán học mà các điểm là vô cùng nhỏ. Các điểm trên màn hình nằm giữa các pixel. Vì vậy, một dòng được vẽ từ (3,5) đến (10,5) có chiều dài 7 và chiếm 7 pixel. Trong tọa độ ngày nay, dòng đó sẽ có độ dài 8.
Barry Brown

@Barry: Điều đó có ý nghĩa, vì nó đã sử dụng XOR rất nhiều và nếu bạn xâu chuỗi các dòng lại với nhau, bạn muốn chúng kết nối mà không thiếu một pixel nơi chúng gặp nhau. Tôi thực sự đã xuất bản một bài báo về việc điền vào đa giác, xem xét cả hai hệ tọa độ.
Mike Dunlavey

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

Chúng ta có thể định nghĩa cả Pb & Pc, do đó:

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

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

Vì vậy, không cần xác định tất cả bốn điểm do tính đối xứng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.