Як перевірити, чи 4 точки утворюють квадрат?


35

Припустимо, у мене є 4 точки (вони двовимірні), які відрізняються один від одного, і я хочу знати, чи утворюють вони квадрат. Як це зробити? (нехай процес буде максимально простим.)


3
Я вважаю, що вам потрібно буде враховувати повернені квадрати?
Martijn Pieters

Чи взагалі є інформація про порядок балів? Тобто ви можете сказати, чи дві точки сусідні, чи утворюють діагональ? (цю інформацію можна використовувати для спрощення процесу)
Даніель Б

1
@DanielB Іншої інформації немає. Так само, як у мене є білий папір і намалюйте на ньому 4 бали випадковим чином. Тоді я хочу знати, чи утворюють вони квадрат.
МаршалSHI

5
Особливо, якщо точки представлені у вигляді чисел з плаваючою точкою, корисно включити почуття "толерантності" в будь-яке із порівнянь, запропонованих нижче. Точні перевірки рівності можуть не дати результатів операцій з плаваючою точкою, навіть коли ми, люди, вважатимемо їх "досить близькими".
Стефан А. Терре

Це пахне питанням домашнього завдання. Не те, що в цьому щось не так. : / whathaveyoutried.com
Джим Г.

Відповіді:


65

Якщо припустити, що ваш квадрат може бути повернутий проти будь-якої системи координат у вас є, ви не можете розраховувати на те, що у ваших чотирьох точках буде повторення значень X і Y.

Що ви можете зробити, це обчислити відстані між кожною з чотирьох точок. Якщо ви вважаєте, що це правда, у вас є квадрат:

  1. Є дві точки, скажімо, A і C, які відстані x одна від одної, і дві інші точки, скажімо B і D, які також відстань x одна від одної.

  2. Кожна точка {A, B, C, D} - це однакова відстань від двох точок, які не відходять x . тобто: Якщо A знаходиться на відстані x від С, то він буде від z і від B, і від D.

Між іншим, відстань z повинна бути SQRT (( x ^ 2) / 2), але вам це не потрібно підтверджувати. Якщо умови 1 і 2 вірні, то у вас квадрат. ПРИМІТКА. Деякі люди стурбовані неефективністю квадратного кореня. Я не казав, що ви повинні робити цей розрахунок, я просто сказав, що якщо ви це зробите, ви отримаєте передбачуваний результат!

Ілюстрація квадратних правил

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

  • AB = z
  • AC = x
  • AD = z

Оскільки AB = AD, перевірте BD:

  • BD = x

Щоб переконатися, вам потрібно перевірити інші сторони: BC та CD.

  • BC = z
  • CD = z

Оскільки AC = BD і оскільки AB = AD = BC = CD, то це квадрат.

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


Реалізація робочого прикладу

Я створив робочий приклад на jsfiddle (див. Тут ). У своєму поясненні алгоритму я використовую довільні точки A, B, C та D. Ці довільні точки трапляються у певному порядку заради проходження прикладу. Алгоритм працює , навіть якщо точки знаходяться в іншому порядку, однак, приклад не обов'язково працювати , якщо ці точки знаходяться в іншому порядку.


Дякуємо: meshuai, Blrfl, MSalters та Bart van Ingen Schenau за корисні коментарі для покращення цієї відповіді.


19
Ви можете коротко замикати цей процес і не турбуватися про те, як упорядковані точки, вимірюючи відстань між ними та відстежуючи кількість унікальних відстаней, які ви знайдете. Коли ви перевищуєте два ( x і z Джоеля ), фігура не є квадратом.
Blrfl

3
Іншою оптимізацією було б порівняння відстаней у квадраті, а не відстаней.
vaughandroid

4
@Blrfl: Ваш тест не працює. Нехай ABCD - ромб з AB = BC = CD = DA = 1, AC = 1 теж (коротка діагональ), тоді AD ~ 1.7 (довга діагональ) / У вас є лише дві довжини x і z, але цифра не є квадратом .
MSalters

2
@JoelBrown: Можна створити форму трапеції з діагоналями AC = BD = x, сторони AB = BC = AD = z і остання сторона CD = y! = Z.
Барт ван Інген Шенау

2
Досить справедливо, зауважте, що ОП чітко сказала 2 виміри.
Джоел Браун

24

Виберіть три з чотирьох пунктів.

З'ясуйте, чи це правильний рівнобедрений трикутник, перевіривши, чи один з трьох векторів між точками дорівнює іншому, повернутий на 90 градусів.

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

Зауважте, що для цього не потрібні дорогі квадратні корені, навіть не множення.


Одна з двох хороших відповідей. Не використовуйте, sqrtякщо не вирішальне значення! Вам не потрібно деградувати цілочисельні обчислення до FP ... не кажучи вже про погіршення точності обчислення FP.
K.Steff

Дякую. хороший.
МаршалШІ

Тепер це правильний спосіб зробити це. Множення тут справді не потрібно.
ПРИЙДАЄТЬСЯ

Як виявити, якщо 2 вектори перпендикулярні один одному без їх крапкового добутку, який передбачає множення?
Pavan Manjunath

1
(x, y), що обертається на прямий кут, дорівнює (-y, x) або (y, -x), залежно від того, обертаєтесь ви у відповідному чи негативному напрямку відповідно.
starblue

17

Я думаю, що найпростішим рішенням є наступне:

  • Спочатку обчисліть центр 4-х балів: center = (A + B + C + D)/4

  • Потім обчисліть вектор A - center. Нехай це будеv := (x,y)

  • Нехай v2вектор vповертається на 90 градусів:v2 := (-y, x)

  • Тепер інші пункти повинні бути center - v, center + v2і center - v2.

Перевага цього рішення полягає в тому, що вам зовсім не доведеться використовувати квадратні корені.


2
Так. Це є найбільш зрозумілим і, мабуть, найпростішим для здійснення також.
Ерік Г

Схоже, векторна рівність сегментів. Чи може хто-небудь, будь ласка, розробити або довести, чому це працює?
vCillusion

Він не виходить спеціально для випадку (0,0), (2,1), (3, -1), (1, -2) - квадрат, не вирівняний до осі
vCillusion

1
Це працює для цього випадку. Центральна точка дорівнює (1,5, -0,5), перша точка - (0, 0), а три інші точки - (1,5, -0,5) + (1,5, -0,5) = (3, -1); (1,5, -0,5) + (0,5, 1,5) = (2, 1) і (1,5, -0,5) - (0,5, 1,5) = (1, -2), це означає, що це квадрат. Доказом є .. симетрія?
aragaer

1
"Рішення відстані" потребує квадратних коренів, але є "рішення квадратної відстані", якого немає. Ваші можуть бути ще ефективнішими ...
maaartinus

5

Вибачте, але деякі відповіді не застосовуються.

У випадку, коли ви вимірюєте 3 ребра (скажімо, AB, AC і AD), виявите, що два мають однаковий розмір (скажімо, AC і AD), а один - більший (скажімо, AB). Тоді ви б виміряли компакт-диск, щоб побачити, чи є він однакового розміру AB, і ви виявите, що він є. Замість квадрата ви можете мати малюнок нижче, і це робить його неправильним рішенням.

Не квадрат ...

Тоді ви спробуйте якесь інше рішення: хоча б раз виміряйте всі відстані: AB, AC, AD, BC, BD, CD. Тоді ви виявляєте, що 4 тоді рівні, а інші 2 також рівні між собою. Але ви могли просто мати малюнок, як показано нижче:

І це теж не квадрат ...

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

Одне можливе рішення: якщо два рівні заходи не з'єднають одну і ту ж точку. Отже: якщо AB і CD однакові по довжині, всі інші комбінації (AC, AD, BC, BD) також рівні, у вас квадрат. Якщо у вас однакова точка, яка робить найбільшу довжину (AB і AC є найбільшою, а всі інші рівні), у вас є одне із зображень, наведених вище.


ні, його алгоритм сказав, що два ребра відстані x не поділяють крапки. але ви просто поділяєте C. Отже, припустимо, що AC є x, тоді BD повинен бути іншим x замість вашого BC.
МаршалSHI

3

Нехай чотири точки мають вектори координат a, b, c, d.

Тоді давайте назвемо їх різниці w = (ad), x = (ba), y = (cb), z = (dc).

Тоді w є ортогональним до a, якщо ви можете створити w за допомогою обертання на 90 градусів. Математично матриця обертання на 90 градусів у 2-просторі дорівнює ((0, -1), (1, 0)). Таким чином, умова, чи w - повернутий на 90 градусів, призводить до

(w_1 == -x_2 та w_2 == x_1)

Якщо це має місце, то вам потрібно перевірити, що w == -y і x == -z, або

((w_1 == -y_1 і w_2 == -y_2) і (x_1 == -z_1 і x_2 == -z_2))

Якщо ці три відношення дотримуються, a, b, c, d складають орієнтований квадрат.


1
Я думаю, що прямокутник також може задовольнити ваші умови.
МаршалSHI

Ні, перша умова не відповідає ортогональним, але не однаково подовженим векторам.
Марк Сальцер

1
так, я просто пропускаю перший. Але 4 бали не впорядковані. Отже, нам потрібно більше кроків, я думаю, щоб підтвердити.
МаршалSHI

Так ... якщо жодна розумніша ідея не виникає, потрібно зациклюватися. Я думаю, що для розрахунку w, x, y, z для кожного можливого впорядкування a, b, c, d та однієї внутрішньої петлі потрібен зовнішній цикл для кожного можливого впорядкування кортежу w, x, y, z.
Марк Сальцер

2

Схожий на відповідь від starblue

Виберіть будь-які три з чотирьох пунктів.

Шукайте серед них праву кутову вершину : Перевіряючи, чи крапковий добуток будь-якого з трьох векторів дорівнює нулю. Якщо не знайдено, не квадрат.

Перевірте, чи вершини, що прилягають до цього кута, теж під кутом. Якщо ні, не квадрат.

Перевірте, чи діагоналі перпендикулярні : Якщо крапковий добуток векторів між першою та четвертою вершиною та двома іншими вершинами (діагоналями) дорівнює нулю, то його квадрат.


Гарна ідея, але все ж потрібно перевірити, що четверта вершина знаходиться на правильній відстані від інших точок. Ви лише перевіряєте, чи знаходиться він по діагоналі.
starblue

@starblue Правильно! Інакше він може сформувати змія. Оновлено.
Макс

2

Я думаю, ви можете зробити це простим додаванням і відніманням і знаходженням min / max. Умови (відповідає схемі інших людей):

  • Точка з найвищим значенням y => A
  • найвищий х => В
  • найнижчий y => C
  • найнижча х => D

Якщо 4 бали поділяють лише 2 x значення та 2 y значення, у вас є рівень рівня.

В іншому випадку у вас є квадрат, якщо ваші точки задовольняють наступному:

  • Ax + Cx = Bx + Dx
  • Ay + Cy = By + Dy
  • Ай - Cy = Bx - Dx

Пояснення: відрізки рядків AC та BD повинні зустрічатися в їх середині. Таким чином (Ax + Cx) / 2 є серединою точки змінного струму, а (Bx + Dx) / 2 - серединою точки BD. Помножте кожну сторону цього рівняння на 2, щоб отримати моє перше рівняння. Друге рівняння - те саме, що і для значень Y. Діамантові форми (ромбовиди) задовольнять ці властивості, тому вам потрібно перевірити, чи немає у вас рівних сторін - чи ширина така ж, як і висота. Це третє рівняння.


2

введіть тут опис зображення

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

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

R = (A+B+C+D)/4

Після того, як у вас буде середнє значення, відстань між кожною точкою та середнім значенням має бути однаковим для всіх чотирьох балів.

if(dist(R,A) == dist(R,B) == dist(R,C) == dist(R,D) then
   print "Is Square"
else
   print "Is Not Square"

Редагувати:

Моя помилка. Це скаже вам лише, якщо точки форми були на колі. Якщо ви також перевіряєте відстань між точками, то це має бути квадрат.

if(dist(R,A) == dist(R,B) == dist(R,C) == dist(R,D) AND
  (dist(A,B) == dist(B,C) == dist(C,D) == dist(A,D) then
   print "Is Square"
else
   print "Is Not Square"

Це передбачає, що точки A, B, C, D не перетинаються (як у дійсному порядку намотування).


1

це не відповідь відповідно до встановлених стандартів, але я сподіваюся, що це допомагає:

[Скопійовано із посилання нижче, так що вам не доведеться відкривати посилання] Python 76 символів

def S(A):c=sum(A)/4.0;return set(A)==set((A[0]-c)*1j**i+c for i in range(4))

Функція S приймає список складних чисел як свій вхід (A). Якщо ми знаємо і центр, і один кут квадрата, ми можемо реконструювати квадрат, обертаючи кут на 90,180 та 270 градусів навколо центральної точки (с). На складній площині обертання на 90 градусів щодо початку відбувається шляхом множення точки на i. Якщо наша первісна форма і реконструйований квадрат мають однакові точки, то це, мабуть, був квадрат.

Це було взято з: Визначте, чи 4 точки утворюють квадрат

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


1
Ви можете узагальнити алгоритм тут. Ви посилаєтесь на інший веб-сайт SE, який трохи краще, ніж вказувати на інший сайт, але ми хочемо, щоб відповідь була на цій сторінці, де задається питання. Тепер люди повинні клацати ще раз, щоб дізнатися, що може бути відповіддю.
Martijn Pieters

0

Основна ідея (це відповідає на питання, чи я вносив щось нове, про що бот запитав, коли натиснув, щоб надати відповідь):

  • ромб з рівними діагоналями - квадрат.
  • "максимально простий" включає:
    • немає поділу,
    • немає квадратних коренів,
    • немає розгалуження,
    • без пошуку,
    • відсутність кутової перевірки або
    • немає векторів,
    • ніяких перетворень,
    • немає складних чисел,
    • відсутність багатолінійних функцій та
    • відсутність імпорту спеціальних пакетів (використовуйте лише вбудовані речі).
    • (І ніяких імператорських прихильників!)

Моє рішення в R представлено нижче. Я припускаю, що рівно чотири пункти, і що, згідно з постановкою проблеми, вже було визначено, що бали є унікальними.

sumsq <- function(x) sum(x^2)

quadrances.xy <- function(xy) vapply(
    as.data.frame(t(diff(xy)), optional=T), sumsq, 1)

Дивіться твори Нормана Уайлдбергера, особливо його відео на YouTube ( Справжня риба, реальні цифри, реальні роботи тощо) та його книгу Божественні пропорції для обговорення "квадрації".

xyставиться до свого роду матриця , прийнятої R в plot, pointsі linesфункції.

Застосування as.data.frame- це хитрість, щоб змусити R робити речі в стовпцях.

optional=TПоложення виключає імена, які не використовуються, у всякому разі.

quadrances.xy..i2. <- function(xy, i2) vapply(
    as.data.frame(i2, optional=T),
    function(k) quadrances.xy(m[k,]),
    1)

Це функція для обчислення квадрантів між зазначеними точками, де парами точок задаються i2аргументом. i2Символ відноситься до матриці індексу , який має один стовпець , індекс, і 2 елементів на колонці (такий же вигляд матриці , повернене combnфункцією).

quadrance.every.xy <- function(xy, .which=combn(nrow(xy), 2))
        quadrances.xy..i2.(xy, .which)

.whichПредставлений в якості аргументу просто виставити його formalsі спробувати передати те , що відбувається.

is.square.xy <- function(xy) {
    qq <- sort(quadrance.every.xy(xy))
    all(qq[2:4] == qq[1]) && # ALL SIDES (SHORT QUADRANCES) EQUAL
    qq[5] == qq[6] # ALL DIAGONALS (LONG QUADRANCES) EQUAL
}

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

xy <- t(matrix(c(3,0,  7,3,  4,7,  0,4), ncol=4))
xy
#      [,1] [,2]
# [1,]    3    0
# [2,]    7    3
# [3,]    4    7
# [4,]    0    4
is.square.xy(xy)
# [1] TRUE

Зауважте, що перші чотири функції корисні самі по собі, крім питання про чотири моменти.


0

Припустимо чотири точки A = (ax, ay), B = (bx, by), C = (cx, cy), D = (dx, dy), і вони утворюють точки квадрата в упорядкуванні проти годинникової стрілки. Переміщаємо точки так, що A знаходиться в (0, 0), віднімаючи ось від bx, cx і dx, і віднімаючи ay від, cy, і dy, задаючи ax = ay = 0.

Якщо точки - це саме кути квадрата в упорядкуванні проти годинникової стрілки, то, задавши A і B, ми можемо обчислити, де C і D: Ми повинні мати (cx, cy) = (bx - by, bx + by) і (dx, dy) = (-by, bx). Отже, ми обчислюємо відстань у квадраті від місця, де знаходяться C і D, до місця, де вони повинні бути: errC = (cx - bx + by) ^ 2 + (cy - bx - by) ^ 2, і errD = (dx + by) ^ 2 + (dy - bx) ^ 2. Додаємо ці і ділимо на (bx ^ 2 + на ^ 2), даючи err = (errC + errD) / (bx ^ 2 + на ^ 2).

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

Але ми не знаємо впорядкування балів. B і D повинні знаходитися на однаковій відстані від A; якщо ми помножимо це на квадратний корінь на 2, це має бути відстань від А до С. Ми використовуємо це для з'ясування, яка точка є С: Обчислити distB = bx ^ 2 + на ^ 2, distD = dx ^ 2 + dy ^ 2. Якщо distD ≥ 1,5 distB, то ми підміняємо C і D; якщо distB ≥ 1,5 distD, то ми підміняємо C і B. Тепер C правильно.

Ми також можемо визначити, які точки - B і D: Якщо ми здогадалися неправильно, хто з них B, а який - D, то наш обчислення ставить D у абсолютно неправильне місце, прямо навпаки, де воно є. Отже, якщо errD ≥ (bx ^ 2 + by ^ 2), то ми поміняємо B і D.

Це буде правильно розташовувати B, C і D, якщо у нас дійсно є квадрат або хоча б приблизно квадрат. Але якщо у нас немає навіть приблизно квадрата, ми знаємо, що обчислення помилок в кінці покаже це.

Підсумок:

  1. Віднімаємо сокиру від bx, cx, dx. Відняти ay від by, cy, dy.
  2. Нехай distB = bx ^ 2 + по ^ 2, distD = dx ^ 2 + dy ^ 2.
  3. Якщо distD ≥ 1,5 * distB, поміняйте місцями C і D і обчисліть distD ще раз.
  4. В іншому випадку, якщо distB ≥ 1,5 * distD, поміняйте місцями B і C і обчисліть distB знову.
  5. Нехай errD = (dx + by) ^ 2 + (dy - bx) ^ 2.
  6. Якщо errD ≥ distB, тоді поміняйте B і D, поміняйте distB і distD, обчисліть errD ще раз.
  7. Нехай errC = (cx - bx + by) ^ 2 + (cy - bx - by) ^ 2.
  8. Нехай err = (errC + errD) / distB.
  9. Вирішіть, чи є у нас квадрат чи майже квадрат залежно від значення помилки.

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


-3

Рішення схоже на мислячі засоби масової інформації.

Перший крок:

x = (A+B+C+D)/4
f=0
if(dist(x,A) == dist(x,B) == dist(x,C) == dist(x,D) 
   f=1
else
   f=0

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

if(A.B==B.C==C.D==D.A==0)
  f=1
else 
  f=0

if (f==1)
  square
else 
  not square

Тут AB означає крапковий добуток A і B

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