Яка ідея визначення прямокутників з двома точками? [зачинено]


15

Справа не в тому, що це не має сенсу, але це просто спрацьовує незручно 99% часу.

Часто у двовимірній графіці прямокутники ініціалізуються, зберігаються та маніпулюються у вигляді пари точок. Немає конкретної мови,

class Rect:
   p1, p2: point

Більш сенс визначати прямокутник як два значення x і два значення y, як це:

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

З двома пунктами, якщо в якомусь місці вихідного коду ви хочете використовувати значення у верхній частині, ви повинні сказати rect.p1.y (хм, зупиніться і подумайте, це p1 або p2), але з чотирма значеннями як звичайні члени даних, це зрозуміло і прямо: rect.ytop (не потрібно думати!) Використання двох точок означає, що в роботі з вертикаллю вам доведеться заплутати горизонталь; між сторонніми елементами існує стороння залежність.

Як виникла ця двоточна ідея і чому вона зберігається? Чи має якась користь над голою координатами x та y?

ДОБАВЛЕНО ПРИМІТКА: Це питання знаходиться в контексті прямокутників, вирівнюваних XY, таких як у менеджерах Windows та інструментальних інструментах GUI, а не в контексті довільних фігур у програмі малювання та малювання.


8
Ви написали значну кількість коду за допомогою Rects?

6
Прямокутник визначається двома точками, тому представлення їх як двох точок має багато сенсу.
Адам Кросленд

2
Прямокутник природніше визначається як діапазон значень x та діапазон значень y.
DarenW

2
Чудове запитання! Я ніколи про це не думав, але ти робиш цікавий аргумент! FWIW, у Windows є РЕКТ, як ви описуєте також (верхній, лівий, нижній, правий)
Дін Хардінг

3
Як визначити прямокутник з двома точками? Чи передбачається, що немає обертання?
Нік Т

Відповіді:


8

Чи вважали ви, що вона менш схильна до помилок?

Якщо ви використовуєте (Point1, Point2), тоді буде дуже зрозуміло, що ви вказуєте. Якщо ви надаєте 2 бали, то єдиною можливою помилкою є те, що користувач змішав свої х і у при побудові балів, оскільки порядок балів не має значення.

Якщо ви надаєте 4 цілих числа, то, якщо хтось не звертає уваги, він може подавати (x1, x2, y1, y2), коли ви хотіли (x1, y1, x2, y2) або навпаки. Також деякі API, такі як Rect структура WCF, визначають прямокутник як (x, y, ширина, висота), який може потім викликати плутанину щодо того, що означає (1, 2, 3, 4). Це (x, y, w, h) або (x1, y1, x2, y2) чи (x1, x2, y1, y2)?

Загалом, (Point1, Point2) мені здається трохи безпечнішим.


3
А як щодо чогось типу Rect (xrange (x1, x2), yrange (y1, y2))? Це здається найвищою безпекою та елегантністю використання API.
DarenW

9

Мені завжди подобалося визначати прямокутник як точку + ширину та висоту, де точка - верхній лівий кут прямокутника.

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

А потім додайте будь-які методи, необхідні для отримання інших показників. Як і версія Java


4
Чи верхній y + висота, y-висота чи просто y?
Камерон Макфарланд

2
@Cameron MacFarland: Це залежить від системи координат програми, що не стосується низького прямокутника.
Джон Перді

2
@Martin Wickman: Яка перевага перед використанням 2 балів?
Крамій

@Kramii: Однією з переваг є те, що потрібно перекласти лише одну точку, якщо ви рухаєте цілу пряму. До речі, ви завжди можете обчислити "відсутність точки", якщо вона вам потрібна (процесор CPU / пам'ять).
Мартін Вікман

Це теж з'являється в реальному житті. Я вважаю це складним, як одна з найпоширеніших речей, яку я роблю з прямокутниками, - це тест, якщо в ній міститься точка. Малювання також поширене. В обох випадках потрібно здійснити додавання, що турбує високопродуктивні лічильники тактових циклів, як я.
DarenW

7

Насправді прямокутник не визначається двома балами. Прямокутник можна визначити лише двома точками, якщо він паралельний осям.

Існує кілька способів зобразити прямокутники, паралельні осям:

  1. Дві діагонально протилежні точки
  2. Одна кутова точка, висота та ширина
  3. Центральна точка, половина висоти та ширини (нечасто, але іноді корисно).
  4. Як дві координати X і дві координати Y

Для (1) багато бібліотек використовують конвенцію, щоб визначити, які два пункти використовуються - наприклад, topLeft і bottomRight, наприклад.

Вибір представлення може бути зумовлений початковою метою визначення прямокутника, але я думаю, що воно часто довільне . Представлення рівнозначні в інформації, яку вони несуть. Однак вони відрізняються легкістю, з якою можна обчислити властивості прямокутника, і зручністю, з якою можна виконувати операції на прямокутнику.

Переваги визначення (1) перед іншими включають:

  • Узгодженість API з іншими багатокутниками, лініями тощо
  • topLeft, bottomRight можна передавати будь-якому методу, який приймає бали
  • Методи класу Point можна викликати на topLeft, bottomRight
  • Більшість властивостей можна отримати легко, наприклад, знизу вліво, вгоріВправо, ширина, висота, центр, довжина діагоналі тощо

6

Що ж, p1: Pointі p2: Pointчи всі у них все одно матимуть дві intкоординати , тож ваш клас не означає одне і те ж?

І якщо ви зберігаєте ці два пункти як першокласні Pointоб'єкти, чи не отримаєте від них трохи більше корисності? У більшості графічних систем координат, про які я знаю, точки підрозділяються таким чином, щоб створити ієрархію об'єктів: point -> circle -> ellipseтощо.

Отже, якщо ви створюєте об'єкт, який не використовує Pointклас, ви розлучили його з рештою ієрархії класів.


1
Перевага, яку я бачу в представленні OP, полягає в тому, що якщо ви хочете знати нижнє значення y прямокутника, ви знаєте, що це "ybottom", де, як і у випадку p1 / p2, вам потрібно розібратися, який з них нижчий. Це, якщо ви не гарантуєте, що у випадку p1 будуть нижчі значення.
Джейсон Віерс

1
Незважаючи на те, що обидві різні структури збиваються до чотирьох координат, версія з двома точками вводить сторонній рівень, який збирає один х і один у, без конкретного обґрунтування, до якого х йде, з якого у. Я не вважаю цей додатковий рівень таким, що забезпечує будь-яку корисність після багатьох років графічного програмування.
DarenW

1
@Jason: Добре. Однак, з ytop/ ybottomпідходом, десь ybottomмає бути гарантія, яка знаходиться внизу ytop.
Учень доктора Вілі

Або зателефонуйте їм y1 та y2, і використовуйте min (y1, y2) та max (y1, y2) - звичайно, це було б незграбніше навіть, ніж доступ через дві точки p1, p2.
DarenW

найменування верхнього / нижнього не купує вам нічого, оскільки нічого не заважає bottomx <topx, якщо ви спеціально не кодуєте це. Я думаю, це просто додасть плутанини.
lkg

5

Ось чому мені подобаються Delphi TRect. Він визначається як варіант запису (об'єднана структура на C-говорі), який можна інтерпретувати як топ TopLeft і BottomRight, або цілі числа Top, Left, Bottom та Right, що б не було зручніше на даний момент.


1
Так, дуже корисна функція, яка.
Увімкнення

4

Звичайно, якщо ви визначите свій прямокутник як:

class Rect
{
    Point bottomLeft;
    Point topRight;
}

то ви відразу знаєте, яка точка є.

Ще краще було б додати додаткові властивості, які дозволять вам маніпулювати прямокутником, коли б вам не знадобилось для вашої програми. Вони будуть просто оновлювати базову структуру даних.

Додавши перетворення до форми, ви можете орієнтувати свій прямокутник будь-яким способом. Вам все одно знадобиться вікно з обмеженням для вирівнювання по осі для швидкого прийому / відхилення чеків :)

Однак якщо ваша модель дозволяє прямокутники в будь-якій орієнтації без застосування перетворення, то "знизу вліво" і "вгорі праворуч" не мають значення, що призводить назад до "p1" і "p2" (або чогось еквівалентного).


То що відбувається, коли ви обертаєте прямокутник на 90 градусів? Тепер ви відстежуєте дві різні точки, ніж ви були спочатку, або ваш "topRight" зараз зліва від "bottomLeft"?
Інаіматі

@Inaimathi - якщо ви додасте матрицю перетворення, ви можете тримати прямокутник, орієнтований на осі. Однак це залежить від вашої заявки.
ChrisF

2

я думаю, що має більше сенсу прямокутник бути представлений х і у мірою та крапкою; Ви навіть можете зробити точку розташування центром прямокутника, щоб воно було незалежним від обертання

але, мабуть, найпростіше було кодувати це як два моменти!


Як було б простіше зафіксувати дві точки?
DarenW

@DaremW: типові функції бібліотеки прямокутника малювання беруть точки вліво-вліво та внизу праворуч
Стівен А. Лоуе

Але чому такі API створені саме так? До того ж бездумно наслідуючи більш ранні бібліотеки, тобто.
DarenW

@DarenW: я можу припустити, що бібліотеки використовують звичайну схему малювання Брезена, яка приймає два моменти як вхідні дані і є дуже ефективною
Стівен А. Лоу

2

Мені це не подобається, тому що ми викинули потенційну ступінь свободи, яка по суті дозволяє довільну ротацію. Загальний прямокутник 2D має п'ять невідомих (ступенів свободи). Ми могли б вказати їх як координати точки, довжини двох сторін, які утворюють вершину з цією точкою, та кута від горизонталі першого рядка (другий вважається кутом на 90 градусів більшим). Нескінченна кількість інших можливостей також може бути використана, але необхідно вказати п’ять незалежних величин. Деякі варіанти ведуть до легшої алгебри, ніж інші, залежно від того, що з ними робиться.


5
Важливо усвідомити, що "стандартна" структура прямокутника - це не строго визначений математичний прямокутник, а спрощена версія, яка завжди паралельна осям X і Y, тому що вона була створена для використання для однієї дуже конкретної речі: визначення прямокутних областей для вікна-менеджера, які (майже) завжди паралельні осям X і Y.
Мейсон Уілер

+1, структура ліво / право / верх / низ знижується, і тому має менше інформації
Хав'єр

Хороший момент, приблизно xy вирівняні прямокутники. Я мав на увазі це, а також розширення, які використовуються в 3D-моделюванні, і деякі інші речі, але всі xy (можливо, також -z) вирівняні.
DarenW

1

Хіба це не те саме, що 2 бали? Як це незручно ... Більшість процедур малювання вимагають очок, а не окремих x / y компонентів.


1

Визначення прямокутників як точкових пар дозволяє повторно використовувати точку як вершину для іншої форми. Просто думка...


Але схоже, граючи з половиною колоди, щоб утримати лише два моменти, щоб визначити чотиригранну форму. Якщо вам потрібен верхній лівий, прохолодний, але якщо вам потрібен верхній правий, вам доведеться зробити певні захоплення даних, відносно кажучи.
DarenW

якщо є аксесуар, який визначається як точка AX точки BY і точка BX точка AY, це полегшує його в пам'яті / на диску, я думаю, щоб зберігати в половині більше вершин і просто вказувати на них (залежно від максимального розміру сітки). Я розумію, куди ви їдете з думкою про діапазон, але ви не граєте з половиною колоди, просто не зберігаєте дублікатів даних .... а інші моменти, які слід зробити, - які обмеження пам'яті? які наслідки для повторної реалізації відображаються у всіх взаємопов'язаних кодах.
RobotHumans

і оскільки вам не потрібно робити жодної "роботи", щоб вийняти з пам'яті перші дві вершини, це, мабуть, швидше
RobotHumans

1

Я вважаю, що це головним чином встановлення рівномірності між усіма примітивними формами.

Впевнені, що ви можете визначити прямокутник багатьма різними способами, але як визначити трикутник, зірку чи коло таким чином, щоб можна було використовувати подібні структури даних?

Всі багатокутники можна визначити за їх точками, з короткою логікою, щоб визначити, що робити з точками.

Графічні бібліотеки функціонують в основному на цих полігонах з точки зору вершин і ребер, тому точки і лінії між ними всі обчислення працюють за цими двома ознаками, добре, що і гранями, але це саме по собі є лише функцією ребер.


1

У двох вимірах зберігання прямокутника як двох точок зрозуміліше, ніж визначення конкретного кута та ширини та висоти - врахуйте негативну ширину чи висоту, або розрахунки, необхідні для визначення кожного варіанту з іншого.

Виконувати обертання прямокутника, визначеного точками, також набагато простіше, ніж один, визначений з точкою плюс ширина та висота.

Я очікую, що інкапсуляція зробить цю диференціацію неважливою як користувач класу.

Прямокутник слід визначити як три точки, які слід добре визначити в 3 вимірах. Я не зовсім впевнений у вимозі визначення прямокутника у 4 та більше вимірах.


1

Це абсолютно довільно. Щоб намалювати прямокутник, вам потрібно чотири частини інформації. Дизайнер (и) бібліотеки вирішили представити її двома точками (кожна з координатою xy), але легко могли це зробити з x / y / w / h або top / bottom / left / right.

Я думаю, справжнє питання ОП: чому саме цей вибір був зроблений?


1

Вибір параметрів важливий лише для дизайнерів / кодерів низького рівня.

Користувачам високого рівня потрібно лише думати про:

  • IsPointInRect
  • Площа
  • Перехрестя (або відсікання)
  • HasOverlap (те саме, що перехресть. Зона> 0)
  • Союз (стає списком прямокутників)
  • Віднімання (перелік прямокутників, що представляють той самий набір точок, який знаходиться в прямій А, але не в прямій B)
  • Перетворити
    • Зсуви в X і Y
    • Обертання (0, 90, 180, 270)
    • Масштабування в X і Y (див. Примітку)
  • Простий синтаксис для властивостей Xmin, Xmax, Ymin, Ymax, Width, Height, щоб користувачеві не потрібно було знати точний вибір параметрів.

Примітка. Для того, щоб мінімізувати втрати точності під час трансформації масштабування, іноді доцільно реалізувати другий клас Rect, який використовує координати з плаваючою комою, щоб проміжні результати могли бути точно збережені в послідовності перетворень і лише округлені до цілого числа в останній крок


0

Як говорить @Steven, я думаю, що це має бути з точки зору однієї (x, y) точки та вектора розміру (w, h). Це тому, що легко впасти в неоднозначність. Припустимо, у вас є наступний заповнений прямокутник, починаючи з точки (0,0).

  012
0 XXX
1 XXX
2 XXX

Зрозуміло, що це ширина, висота (3,3), але що це за другий момент? Це (2,2) чи (3,3)?

Ця неоднозначність може викликати всілякі проблеми.

Я дізнався насилу років тому , що краще думати про графічних координатах , як лінії між пікселями, а не як лінії пікселів на . Таким чином, немає двозначності.


2
Оригінальні програми QuickDraw на Mac (ті, які були з 1980-х) використовували математичну модель, що балів було нескінченно мало. Точки на екрані лежать між пікселями. Отже лінія, проведена від (3,5) до (10,5), мала довжину 7 і займала 7 пікселів. За сьогоднішніми координатами ця лінія мала б довжину 8.
Баррі Браун

@Barry: Це має сенс, оскільки він багато використовував XOR, і якщо ви з'єднуєте рядки разом, ви хочете, щоб вони з'єдналися без пропущеного пікселя там, де вони зустрічаються. Я фактично опублікував довідковий документ про заповнення полігонів, враховуючи обидві системи координат.
Майк Данлаве

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

Ми можемо визначити обидва Pb & Pc таким чином:

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

і

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

Тому немає необхідності визначати всі чотири точки через симетрію

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.