Como verificar se 4 pontos formam um quadrado?


35

Suponha que eu tenha 4 pontos (são bidimensionais), que são diferentes um do outro, e quero saber se eles formam um quadrado. Como fazer isso? (deixe o processo o mais simples possível.)


3
Suponho que você precisaria considerar quadrados girados?
Martijn Pieters

Você tem informações sobre a ordem dos pontos? Ou seja, você pode dizer se dois pontos são adjacentes ou formam uma diagonal? (esta informação pode ser usada para simplificar o processo)
Daniel B

1
@DanielB Nenhuma outra informação. É como se eu tivesse um papel branco e desenhasse 4 pontos aleatoriamente. Então eu quero saber se eles formam um quadrado.
MarshalSHI

5
Especialmente se os pontos são representados como números de ponto flutuante, é útil incluir um senso de "tolerância" em qualquer uma das comparações sugeridas abaixo. As verificações exatas de igualdade podem falhar nos resultados das operações de ponto flutuante, mesmo quando os humanos as consideram "próximas o suficiente".
Stephan A. Terre

Isso cheira a uma pergunta de lição de casa. Não que haja algo errado nisso. : / whathaveyoutried.com
Jim G.

Respostas:


65

Supondo que seu quadrado possa ser girado em relação ao sistema de coordenadas que você possui, não se pode confiar na repetição dos valores X e Y em seus quatro pontos.

O que você pode fazer é calcular as distâncias entre cada um dos quatro pontos. Se você acha que o seguinte é verdadeiro, você tem um quadrado:

  1. Existem dois pontos, digamos A e C, que estão à distância x um do outro, e dois outros pontos, digamos B e D, que também estão à distância x um do outro.

  2. Cada ponto {A, B, C, D} está a uma distância igual dos dois pontos que não estão x afastados. ie: Se A está x longe de C, então ele estará z longe de B e D.

Aliás, a distância z terá que ser SQRT (( x ^ 2) / 2), mas você não precisa confirmar isso. Se as condições 1 e 2 forem verdadeiras, você terá um quadrado. NOTA: Algumas pessoas estão preocupadas com a ineficiência da raiz quadrada. Não disse que você deveria fazer esse cálculo, apenas disse que se o fizesse obteria um resultado previsível!

Ilustração das Regras Quadradas

O mínimo de trabalho que você precisaria fazer seria escolher um ponto, digamos A e calcular a distância para cada um dos outros três pontos. Se você puder descobrir que A é x de um ponto e z de dois outros pontos, basta verificar esses dois outros pontos um contra o outro. Se eles também são x um do outro, então você tem um quadrado. ou seja:

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

Como AB = AD, verifique BD:

  • BD = x

Só para ter certeza, você precisa verificar os outros lados: BC e CD.

  • BC = z
  • CD = z

Como AC = BD e AB = AD = BC = CD, esse é, portanto, um quadrado.

Ao longo do caminho, se você encontrar mais de duas distâncias distintas, a figura não poderá ser um quadrado, para que você possa parar de procurar.


Exemplo de trabalho de implementação

Eu criei um exemplo de trabalho no jsfiddle (veja aqui ). Na minha explicação do algoritmo, utilizo os pontos arbitrários A, B, C e D. Esses pontos arbitrários estão em uma determinada ordem, a fim de percorrer o exemplo. O algoritmo funciona mesmo que os pontos estejam em uma ordem diferente; no entanto, o exemplo não funciona necessariamente se esses pontos estiverem em uma ordem diferente.


Agradecemos a: meshuai, Blrfl, MSalters e Bart van Ingen Schenau pelos comentários úteis para melhorar esta resposta.


19
Você pode causar um curto-circuito neste processo e não se preocupar com a forma como os pontos são ordenados, medindo a distância entre eles e mantendo o controle do número de distâncias únicas encontradas. Depois que você exceder dois (Joel x e z ), a figura não é um quadrado.
Blrfl

3
Outra otimização seria comparar as distâncias ao quadrado, em vez das distâncias.
vaughandroid

4
@Blrfl: Seu teste não funciona. Seja ABCD um diamante com AB = BC = CD = DA = 1, AC = 1 também (diagonal curta) e, em seguida, AD ~ 1,7 (diagonal longa) / Você tem apenas dois comprimentos x e z, mas a figura não é um quadrado .
MSalters

2
@JoelBrown: É possível criar uma forma de trapézio com as diagonais AC = BD = x, os lados AB = BC = AD = z e o último lado CD = y! = Z.
Bart van Ingen Schenau,

2
Justo, observe, no entanto, que o OP disse explicitamente duas dimensões.
Joel Brown

24

Escolha três dos quatro pontos.

Descubra se é um triângulo isósceles direito, verificando se um dos três vetores entre pontos é igual a outro girado em 90 graus.

Nesse caso, calcule o quarto ponto por adição de vetor e compare-o com o quarto ponto fornecido.

Observe que isso não requer raízes quadradas caras, nem mesmo multiplicação.


Uma das duas boas respostas. Não use a sqrtmenos que seja crucial! Você não precisa degradar cálculos inteiros para FP ... para não mencionar piorar a precisão do cálculo FP.
K.Steff

THX. uma boa.
MarshalSHI

Agora esse é o caminho certo para fazê-lo. De fato, a multiplicação não é necessária aqui.
Vem

Como você descobre se 2 vetores são perpendiculares um ao outro sem o produto escalar que envolve multiplicação?
Pavan Manjunath

1
(x, y) girado em um ângulo reto é (-y, x) ou (y, -x), dependendo de você girar na direção positiva ou negativa, respectivamente.
Starblue #

17

Eu acho que a solução mais fácil é a seguinte:

  • Primeiro, calcule o centro dos 4 pontos: center = (A + B + C + D)/4

  • Depois calcule o vetor A - center. Deixe isso serv := (x,y)

  • Seja v2o vetor vgirado em 90 graus:v2 := (-y, x)

  • Agora os outros pontos devem ser center - v, center + v2e center - v2.

A vantagem desta solução é que você não precisa usar raízes quadradas.


2
Sim. Este é o mais compreensível e provavelmente o mais fácil de implementar também.
Eric G

Parece igualdade de vetor de segmentos. Alguém por favor pode elaborar ou provar por que funciona?
VCillusion

Ele não especificamente para o caso do (0,0), (2,1), (3, -1), (1, -2) - quadrados não alinhado ao eixo
vCillusion

1
Funciona para este caso. O ponto central é (1,5, -0,5), o primeiro ponto é (0, 0) e três outros pontos são (1,5, -0,5) + (1,5, -0,5) = (3, -1); (1,5, -0,5) + (0,5, 1,5) = (2, 1) e (1,5, -0,5) - (0,5, 1,5) = (1, -2), o que significa que é um quadrado. A prova é .. simetria?
Aragaer

1
A "solução à distância" precisa de raízes quadradas, mas há a "solução à distância ao quadrado", que não precisa de nenhuma. O seu pode ser ainda mais eficiente ...
maaartinus 18/11

5

Sinto muito, mas algumas respostas não se aplicam.

Para o caso, você mede 3 arestas (digamos AB, AC e AD) para descobrir que duas têm o mesmo tamanho (digamos AC e AD) e uma é maior (digamos AB). Então você mede o CD para ver se é do mesmo tamanho de AB e descobre que é. Em vez de um quadrado, você pode ter a figura abaixo, e isso a torna uma solução errada.

Não é um quadrado ...

Depois, tente outra solução: meça todas as distâncias pelo menos uma vez: AB, AC, AD, BC, BD, CD. Então você descobre que 4 deles são iguais e os outros 2 também são iguais entre si. Mas você pode ter uma foto como abaixo:

E isso também não é um quadrado ...

Portanto, essas respostas não estão corretas, apesar dos altos votos que receberam.

Uma solução possível: se as duas medidas iguais não conectam o mesmo ponto. Portanto: se AB e CD são do mesmo comprimento, todas as outras combinações (AC, AD, BC, BD) também são iguais, você tem um quadrado. Se você tem o mesmo ponto de maior comprimento (AB e AC é o maior e todos os outros são iguais), você tem uma das imagens acima.


não, seu algoritmo disse que as duas arestas das distâncias x não compartilham um ponto. mas você apenas compartilha C. Então, assuma que AC é x, então BD deve ser outro x em vez de seu BC.
MarshalSHI

3

Deixe os quatro pontos terem vetores de coordenadas a, b, c, d.

Então vamos chamar suas diferenças w = (ad), x = (ba), y = (cb), z = (dc).

Então w é ortogonal a a se você pode criar w a partir de uma rotação de 90 graus. Matematicamente, a matriz de rotação de 90 graus no espaço 2 é ((0, -1), (1, 0)). Assim, a condição de w ser girado em 90 graus resulta em

(w_1 == -x_2 e w_2 == x_1)

Se isso for válido, será necessário verificar se w == -yex == -z ou

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

Se essas três relações se mantiverem, a, b, c, d formam um quadrado orientado.


1
Eu acho que o retângulo também pode satisfazer suas condições.
MarshalSHI

Não, a primeira condição não é atendida por vetores ortogonais, mas não igualmente longos.
precisa

1
Sim, só sinto falta do primeiro. Mas os 4 pontos não estão ordenados. Então, precisamos de mais etapas, eu acho, para confirmar.
MarshalSHI

Sim ... se nenhuma idéia mais inteligente surgir, é preciso repetir. Eu acho que é preciso um loop externo para calcular w, x, y, z de cada ordem possível de a, b, c, d e um loop interno para cada ordem possível da tupla w, x, y, z.
precisa

2

Semelhante à resposta por starblue

Escolha três dos quatro pontos.

Procure um vértice em ângulo reto entre eles : Verificando se o produto escalar de qualquer um dos dois vetores é zero. Se não for encontrado, não é um quadrado.

Verifique se os vértices adjacentes a esse ângulo também estão em ângulo reto. Caso contrário, não é um quadrado.

Verifique se as diagonais são perpendiculares : se o produto escalar dos vetores entre o primeiro e o quarto vértice e os outros dois vértices (diagonais) for zero, será um quadrado.


Boa ideia, mas você ainda precisa verificar se o quarto vértice está à distância certa dos outros pontos. Você só verifica se está na diagonal.
Starblue #

@starblue Right! Caso contrário, pode formar uma pipa. Atualizada.
Max

2

Eu acho que você pode fazer isso com adição e subtração simples e encontrar min / max. Termos (corresponde ao diagrama de outras pessoas):

  • Ponto com o valor mais alto de y => A
  • maior x => B
  • menor y => C
  • menor x => D

Se 4 pontos compartilham apenas 2 x valores e 2 y, você tem um quadrado nivelado.

Caso contrário, você terá um quadrado se seus pontos satisfizerem o seguinte:

  • Ax + Cx = Bx + Dx
  • Ay + Cy = Por + Dy
  • Ay - Cy = Bx - Dx

Explicação: Os segmentos de linha AC e BD devem se encontrar em seus pontos médios. Assim (Ax + Cx) / 2 é o ponto médio da CA e (Bx + Dx) / 2 é o ponto médio do BD. Multiplique cada lado desta equação por 2 para obter minha primeira equação. A segunda equação é a mesma para os valores Y. As formas em losango (romboides) satisfarão essas propriedades, portanto, é necessário verificar se você possui lados iguais - se a largura é igual à altura. Essa é a terceira equação.


2

insira a descrição da imagem aqui

Existem algumas boas respostas aqui, mas a pergunta foi feita pela abordagem mais simples. Pensei nisso rapidamente e é assim que eu faria.

Você pode dizer se quatro pontos representam um quadrado (mesmo que rotacionado), mas encontrando a média dos quatro pontos.

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

Depois de obter a média, a distância entre cada ponto e a média teria que ser a mesma para todos os quatro pontos.

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

EDITAR:

Meu erro. Isso indicaria apenas se os pontos do formulário estavam em um círculo. Se você também verificar a distância entre os pontos, deve ser um quadrado.

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"

Isso pressupõe que os pontos A, B, C, D não cruzam (como em uma ordem de enrolamento válida).


1

isso não é uma resposta de acordo com os padrões estabelecidos, mas espero que ajude:

[Copiado do link abaixo para que você não precise abrir o link] Python 76 caracteres

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

A função S recebe uma lista de números complexos como entrada (A). Se conhecermos o centro e o canto de um quadrado, podemos reconstruí-lo girando o canto 90.180 e 270 graus em torno do ponto central (c). No plano complexo, a rotação de 90 graus sobre a origem é feita multiplicando o ponto por i. Se a nossa forma original e o quadrado reconstruído tiverem os mesmos pontos, deve ter sido um quadrado.

Isto foi retirado de: Determine se 4 pontos formam um quadrado

Se você gosta da resposta, digo, dedique alguns momentos para agradecer à pessoa ou vote sua resposta nessa página.


1
Você pode resumir o algoritmo aqui. Você está vinculando a outro site SE, que é um pouco melhor do que apontar para outro site, mas queremos que a resposta esteja nesta página, onde a pergunta está sendo feita. Agora, as pessoas precisam clicar novamente para saber qual pode ser a resposta.
Martijn Pieters

0

Ideia básica (isso responde à questão de saber se eu estava contribuindo com algo novo, o que foi perguntado pelo bot quando eu cliquei para fornecer uma resposta):

  • um losango com diagonais iguais é um quadrado.
  • "o mais simples possível" inclui:
    • nenhuma divisão
    • sem raízes quadradas,
    • sem ramificação,
    • sem pesquisa
    • nenhuma verificação ou aquisição de ângulo,
    • nenhum vetor,
    • sem transformações,
    • sem números complexos,
    • nenhuma função multilinha e
    • não há importação de pacotes especiais (use apenas material embutido).
    • (E sem embargos imperiais!)

Minha solução em R é apresentada abaixo. Estou assumindo que existem exatamente quatro pontos e que, pela declaração do problema, já foi determinado que os pontos são únicos.

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

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

Veja os trabalhos de Norman Wildberger, especialmente seus vídeos no YouTube ( peixes reais, números reais, empregos reais e segs.) E seu livro Divine Proportions para uma discussão sobre "quadrance".

xyrefere-se a um tipo de matriz da aceite por R plot, pointse linesfunções.

A aplicação de as.data.frameé um truque para fazer com que R faça as coisas em colunas.

A optional=Tcláusula elimina nomes que, de qualquer maneira, não são usados.

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

Essa é uma função para calcular as quadraturas entre os pontos especificados, onde pares de pontos são especificados pelo i2argumento. O i2símbolo refere-se a uma matriz de índice que possui uma coluna por índice e 2 elementos por coluna (o mesmo tipo de matriz retornado pela combnfunção).

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

O .whichargumento é apresentado como um argumento apenas para expô-lo formalse tentar comunicar o que está acontecendo.

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
}

Eu disse que "simples" não incluía funções de múltiplas linhas. Você terá que desculpar esta função de duas linhas.

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

Observe que as quatro primeiras funções são úteis por si só, além da pergunta sobre os quatro pontos.


0

Suponha quatro pontos A = (ax, ay), B = (bx, by), C = (cx, cy), D = (dx, dy) e eles formam os pontos de um quadrado em ordem anti-horária. Movemos os pontos para que A esteja em (0, 0) subtraindo ax de bx, cx e dx e subtraindo ay de by, cy e dy, definindo ax = ay = 0.

Se os pontos são exatamente os cantos de um quadrado em ordem anti-horária, então, dados A e B, podemos calcular onde C e D estão: Deveríamos ter (cx, cy) = (bx - por, bx + por) e (dx, dy) = (-por, bx). Portanto, calculamos a distância ao quadrado de onde C e D estão, para onde devem estar: errC = (cx - bx + by) ^ 2 + (cy - bx - by) ^ 2 e errD = (dx + by) ^ 2 + (dy - bx) ^ 2. Nós os adicionamos e dividimos por (bx ^ 2 + por ^ 2), dando err = (errC + errD) / (bx ^ 2 + por ^ 2).

O erro resultante seria 0 se um quadrado perfeito, ou um número pequeno se quase um quadrado, e o número permaneceria inalterado, exceto por erros de arredondamento, se convertermos, escalarmos ou girarmos os pontos do quadrado. Assim, podemos usar o erro para decidir o quão bom temos um quadrado.

Mas não sabemos a ordem dos pontos. B e D devem estar à mesma distância de A; se multiplicarmos isso pela raiz quadrada de 2, essa deve ser a distância de A a C. Usamos isso para descobrir qual ponto é C: Calcular distB = bx ^ 2 + por ^ 2, distD = dx ^ 2 + dy ^ 2 Se distD ≥ 1,5 distB, então trocamos C e D; se distB ≥ 1,5 distD, então trocamos C e B. Agora C está certo.

Também podemos descobrir quais pontos são B e D: se adivinhamos errado qual deles é B e qual é D, então nosso cálculo coloca D no lugar completamente errado, exatamente o oposto de onde ele está. Portanto, se errD ≥ (bx ^ 2 + por ^ 2), então trocamos B e D.

Isso organizará B, C e D corretamente se tivermos um quadrado de fato ou pelo menos aproximadamente um quadrado. Mas se não temos nem um quadrado, sabemos que o cálculo do erro no final mostrará isso.

Resumo:

  1. Subtraia o machado de bx, cx, dx. Subtraia ay de por, cy, dy.
  2. Seja distB = bx ^ 2 + por ^ 2, distD = dx ^ 2 + dy ^ 2.
  3. Se distD ≥ 1,5 * distB, troque C e D e calcule distD novamente.
  4. Caso contrário, se distB ≥ 1,5 * distD, troque B e C e calcule distB novamente.
  5. Seja errD = (dx + by) ^ 2 + (dy - bx) ^ 2.
  6. Se errD ≥ distB, troque B e D, troque distB e distD, calcule errD novamente.
  7. Seja errC = (cx - bx + por) ^ 2 + (cy - bx - por) ^ 2.
  8. Deixe err = (errC + errD) / distB.
  9. Decida se temos um quadrado ou quase um quadrado, dependendo do valor de err.

Se soubermos a ordem dos pontos, isso pode obviamente ser simplificado.


-3

A solução é semelhante à mídia pensante.

Primeiro passo:

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

Esta propriedade é seguida por quadrado porque é cíclica. agora um círculo para seguir essa propriedade. então agora verifique

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

if (f==1)
  square
else 
  not square

Aqui AB significa produto escalar de A e B

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.