Seu objetivo é determinar se um determinado ponto 2D X está dentro da área do triângulo com os vértices A, B, C.
Escreva uma função que considere as coordenadas do ponto de teste X e os três vértices do triângulo (totalizando 8 coordenadas) e retorne True se o ponto estiver dentro desse triângulo e False se estiver fora.
Não se preocupe com casos extremos. Se o ponto estiver no limite do triângulo (aresta ou vértice) ou se o triângulo for realmente um segmento de linha, seu código poderá fazer o que for, incluindo travamentos. Também não se preocupe com estabilidade numérica ou precisão de ponto flutuante.
Seu código deve ser uma função nomeada. Trechos de código não serão aceitos.
Menos personagens ganham.
Entrada:
Oito números reais representando coordenadas. Os números estarão no intervalo (-1,1)
.
O formato exato de entrada é flexível. Você pode, por exemplo, coletar oito números, uma lista de oito números, uma lista de quatro pontos, cada uma dada por uma tupla, uma matriz 2 * 4, quatro números complexos, duas listas das coordenadas xe coordenadas y, e assim por diante.
A entrada precisa ser apenas os números em algum contêiner, sem dados adicionais. Você não pode usar a entrada para executar qualquer pré-processamento, nem pode exigir restrições na entrada, como exigir que os pontos sejam dados em coordenadas y ascendentes. Sua entrada deve permitir oito coordenadas (embora seu código possa se comportar arbitrariamente nos casos extremos mencionados anteriormente).
Por favor, indique o seu formato de entrada.
Saída:
O booleano True
/ correspondente False
, o número correspondente 1
/ 0
ou os análogos no seu idioma.
Casos de teste
As entradas recebem uma lista [X,A,B,C]
de quatro tuplas, primeiro o ponto de teste e depois os três vértices do triângulo. Eu os agrupei naqueles cujas saídas deveriam ser True
e aquelas que deveriam ser False
.
True
instâncias:
[(-0.31961, -0.12646), (0.38478, 0.37419), (-0.30613, -0.59754), (-0.85548, 0.6633)]
[(-0.87427, -0.00831), (0.78829, 0.60409), (-0.90904, -0.13856), (-0.80685, 0.48468)]
[(0.28997, -0.03668), (-0.28362, 0.42831), (0.39332, -0.07474), (-0.48694, -0.10497)]
[(-0.07783, 0.04415), (-0.34355, -0.07161), (0.59105, -0.93145), (0.29402, 0.90334)]
[(0.36107, 0.05389), (0.27103, 0.47754), (-0.00341, -0.79472), (0.82549, -0.29028)]
[(-0.01655, -0.20437), (-0.36194, -0.90281), (-0.26515, -0.4172), (0.36181, 0.51683)]
[(-0.12198, -0.45897), (-0.35128, -0.85405), (0.84566, 0.99364), (0.13767, 0.78618)]
[(-0.03847, -0.81531), (-0.18704, -0.33282), (-0.95717, -0.6337), (0.10976, -0.88374)]
[(0.07904, -0.06245), (0.95181, -0.84223), (-0.75583, -0.34406), (0.16785, 0.87519)]
[(-0.33485, 0.53875), (-0.25173, 0.51317), (-0.62441, -0.90698), (-0.47925, 0.74832)]
False
instâncias:
[(-0.99103, 0.43842), (0.78128, -0.10985), (-0.84714, -0.20558), (-0.08925, -0.78608)]
[(0.15087, -0.56212), (-0.87374, -0.3787), (0.86403, 0.60374), (0.01392, 0.84362)]
[(0.1114, 0.66496), (-0.92633, 0.27408), (0.92439, 0.43692), (0.8298, -0.29647)]
[(0.87786, -0.8594), (-0.42283, -0.97999), (0.58659, -0.327), (-0.22656, 0.80896)]
[(0.43525, -0.8923), (0.86119, 0.78278), (-0.01348, 0.98093), (-0.56244, -0.75129)]
[(-0.73365, 0.28332), (0.63263, 0.17177), (-0.38398, -0.43497), (-0.31123, 0.73168)]
[(-0.57694, -0.87713), (-0.93622, 0.89397), (0.93117, 0.40775), (0.2323, -0.30718)]
[(0.91059, 0.75966), (0.60118, 0.73186), (0.32178, 0.88296), (-0.90087, -0.26367)]
[(0.3463, -0.89397), (0.99108, 0.13557), (0.50122, -0.8724), (0.43385, 0.00167)]
[(0.88121, 0.36469), (-0.29829, 0.21429), (0.31395, 0.2734), (0.43267, -0.78192)]
Respostas:
Javascript / ECMAScript 6,
161159158/152Javascript:
Versão ECMAScript 6 (obrigado m.buettner, salva 6 caracteres)
Chame como tal (retorna
true
oufalse
):Usa alguma matemática de coordenadas barocêntricas sofisticada com base no código desta resposta . A seguir, uma versão não-gasta para sua diversão na leitura:
fonte
(a*(l-n)+i*(g-e)+n*e-g*l)
vez de(-g*l+a*(-n+l)+i*(g-e)+n*e)
?Python 2.7
1281271171101091039995949190Minha primeira tentativa de código-golfe!
Código
Toma como entrada (x, y, t) onde (x, y) é o ponto que estamos verificando et é um triângulo t = ((x1, y1), (x2, y2), (x3, y3)).
Explicação
Estou calculando os determinantes das matrizes
Esses determinantes representam as distâncias sinalizadas dos lados do triângulo até o ponto (x, y). Se todos eles tiverem o mesmo sinal, o ponto estará do mesmo lado de todas as linhas e, portanto, estará contido no triângulo.
No código acima,
a*y+c*b+d*x-d*a-c*y-b*x
é um determinante de uma dessas matrizes.Estou usando o fato de que
True+True+True==3
eFalse+False+False==0
para determinar se todos esses determinantes têm o mesmo sinal.Uso os índices de lista negativa do Python usando em
t[-1]
vez det[(i+1)%3]
.Obrigado Peter pela idéia de usar em
s%3<1
vez des in(0,3)
verificar se s é 0 ou 3!Versão Sagemath
Não é realmente uma solução diferente, por isso vou incluí-la nesta resposta, uma solução sábia com 80 caracteres:
onde
p=[x,y]
et=[[x1,y1],[x2,y2],[x3,y3]]
fonte
s in (0,3)
ser reduzido paras%3<1
?-1,0,1 ... t[i]+t[i+1]
é equivalente a0,1,2 ... t[i-1]+t[i]
in -1,0,1
antes de ler isso. Na verdade, seu caminho é mais legível, então eu o usarei de qualquer maneira.sum
se colocar0,1,2
entre parênteses, caso em que um caractere substitui um espaço. O motivo é que o Python permite que a compreensão sem colchetes seja passada para funções, mas as vírgulas na tupla nua o1,2,3
confundem porque ele tenta analisá-las como argumentos separados.Mathematica, 67 bytes
A função usa dois argumentos, o ponto
X
e uma lista de pontos{A,B,C}
, que são referidos como#
e#2
respectivamente. Ou seja, se você ligarentão você terá
#
comoX
e#2
como{A,B,C}
. (Observe que existem duas outras funções anônimas aninhadas dentro do código -#
e#2
têm um significado diferente dentro delas).Aqui está uma explicação da própria função:
Observe que esta função realmente funciona para qualquer n-gon convexo, desde que seus vértices sejam dados no sentido horário ou anti-horário.
fonte
Det
?CJam,
66635952463432313028 caracteresDepois de transformar a cadeia Unicode, o seguinte código ( 33 bytes ) é avaliado:
Espera
X [A B C]
como entrada, onde cada ponto é do formulário[double double]
. A saída é 1 ou 0.Experimente online.
Um grande obrigado a user23013 por salvar 6 caracteres (13 bytes de código não compactado)!
Casos de teste
fonte
{
e}
e tratados como uma única unidade. Semelhante aos blocos de código em C / java, exceto que os blocos são objetos de primeira classe e podem ser atribuídos a variáveis (definindo funções).1m<@m*
prepara 3 pares de X e o próximo (i+1
th) vértice do triângulo.@-@@-
move o (i
v) vértice atual para a origem (e espelhado se não estava@-\@-
, mas não importa).@@*@@*>
calcula o eixo z do produto cruzado, também conhecido como determinante, e retorna1
se for negativo.:+3%!
retorna se são todos iguais, ou seja, todos os 3 são negativos ou não negativos, o que significa positivo, exceto nos casos extremos. Eu acho que é mais desafiador ler CJam do que jogar golfe.{[_1m<\]z\f{f{+~@-@@-}~@@*@@*>})-!}:T
. Use2m>
ouWm<
para segurança Unicode.{2*2/\f{f{+~@-@@-}~@@*@@*>})-!}:T
C - 156 bytes
A entrada é uma matriz de 3 flutuadores em X, 3 flutuadores em Y e separa x e y para o ponto de teste. Bônus: lida com todos os casos extremos!
Adaptado de PNPOLY.
fonte
i;j;c;f(float*X,float*Y,float x,float y){for(c=i=0,j=2;i<3;)c^=(Y[i]>y)-(Y[j]>y)&(x<(X[j]-X[i])*(y-Y[i])/(Y[j]-Y[i])+X[j=i++]);return c;}
137 - testado em javascriptPitão 1.0.5 ,
575451Define a função g, que recebe duas entradas: o ponto de teste e, em seguida, a lista dos vértices do triângulo. Saídas
True
eFalse
. Nota: Destrói a entrada, especificamente b, a lista dos vértices do triângulo.Tente aqui . Os últimos caracteres
gvwvw
chamam a função com um caso de teste nas próximas duas linhas.Baseado em neste algoritmo
Explicação:
A guerra CJam - Pyth continua!
fonte
w
recebendo entrada STDIN?Z
por um conjunto vazio com o qual você acumulaZ|=
e testar seu comprimento para ver se são apenas0
ou1
foram vistos? A estratégia ficou mais longa em Python, mas talvez valha a pena usar as primitivas de Pyth.J
6445 (42 sem atribuição)A atribuição não é necessária para que a coisa seja uma função, portanto, não se deve contar ou não. Aproveitando a entrada flexível: eu gostaria de ter uma matriz de (1 + número de vértices) x (dimensionalidade do espaço).
Esperando marcar alguns pontos extras aqui ...: Essa coisa funciona para qualquer dimensão do simplex, não apenas triângulos em um avião, mas também uma pirâmide de três lados no espaço 3D e assim por diante. Também funciona quando o número de vértices do simplex é menor que (n + 1) e calcula se a projeção do ponto no simplex está dentro ou não.
Ele converte em coordenadas barentêntricas e depois procura por negativas, indicando que o ponto está fora. Se importa J usa _ para negativo
Uma execução nos exemplos fornecidos:
fonte
N+1
vértices máximos . Por exemplo, uma pirâmide de 4 vértices no espaço 3D ou um simplex de 5 vértices no espaço 3D. O número de vértices pode ser menor queN+1
, nesse caso o algoritmo verifica se a projeção ortogonal no hiperplano em que o simplex reside está dentro do simplex ou não (por exemplo, um simplex de 2 pontos em 2-D será projetado na linha e verificado mentiras se esta projecção entre os pontos finais)Caracteres HTML5 + JS, 13b + 146b / 141b / 114
HTML:
JS (146b):
ou ES6 (141b):
ou ES6 ofuscado por unicode (114 caracteres):
demo: http://jsfiddle.net/xH8mV/
Ofuscação Unicode feita com: http://xem.github.io/obfuscatweet/
fonte
Python (65)
As pessoas parecem ter terminado de enviar, então postarei minha própria solução na minha pergunta.
X
é o número complexo que representa os pontos de teste eL
é uma lista de três pontos, cada um um número complexo.Primeiro, explicarei uma versão menos golfe do código;
Mudamos os pontos
A,B,C,X
para queX
estejam na origem, aproveitando a aritmética complexa interna do Python. Precisamos verificar se a origem está contida no casco convexo deA,B,C
. Isso é equivalente à origem sempre no mesmo lado (esquerdo ou direito) dos segmentos de linha AB, BC e AC.Um segmento
AB
tem a origem à esquerda, se se deslocar no sentido anti-horário a menos de 180 graus, para ir de A a B, e à direita, caso contrário. Se considerarmos os ângulosa
,b
ec
correspondentes a esses pontos, isso significab-a < 180 degrees
(ângulos tomados no intervalo de 0 a 360 graus). Como números complexosangle(B/A)=angle(B)/angle(A)
,. Além disso,angle(x) < 180 degrees
exatamente para apontar no meio plano superior, que verificamos viaimag(x)>0
.Portanto, se a origem está à esquerda de AB, é expresso como
(A/B).imag>0
. Verificar se todos são iguais para cada par cíclicoA,B,C
indica se o triânguloABC
contém a origem.Agora, voltemos ao código totalmente golfado
Geramos cada par cíclico
(A-X,B-X,C-X)=(L[0]-X,L[1]-X,L[2]-X)
, aproveitando os índices negativos da lista Python envolvendo (L[-1]
=L[2]
). Para verificar se os Bools são todosTrue
(1
) ou todosFalse
(0
), nós os adicionamos e verificamos a divisibilidade em 3, como muitas soluções.fonte
Fortran -
232218195174Horrível. A função é horrível devido ao requisito de que os dados sejam passados para ela e não podemos pré-processá-los.
A diminuição de 14 caracteres é porque eu esqueci de jogar o nome da função nos meus testes. A diminuição adicional se deve à digitação implícita e ao esquecimento de alterar o nome da função. Os próximos 20 caracteres saíram devido à leitura nos pontos como uma única matriz. O programa completo é
fonte
logical function T(x);real x(8);p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3);s=x(6)-x(4);u=x(7)-x(3);v=x(8)-x(4);o=r*v-u*s;T=ALL([p*(s-v)+q*(u-r)+o,p*v-q*u,q*r-p*s]>=o);end
tentei abreviá-lo ainda mais usando operações de lista, mas infelizmente isso não funcionou muito bem.logical function T(x);real x(8);p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3);s=x(6)-x(4);u=x(7)-x(3);v=x(8)-x(4);a=r*v-u*s;b=p*v-q*u;d=q*r-p*s;T=ALL([a-b-d,b,d]>=a);end
espero não ter cometido nenhum erro nas transformações! Embora pareça que seu código original não passa em todos os casos de teste.True
exemplo no OP dáFalse
se eu trocarB
eC
valores 's, enquanto dandoTrue
para a orientação original.a < 0
, que inverte efetivamente a condição que você precisa testar. Infelizmente, isso não pode ser corrigido apenas envolvendo tudo em umabs
, como então a condição implícitab
ed
o mesmo sinal dea
se perder. Isso pode ser corrigido usando algo como (novamente, reutilizando a notação e as variáveis predefinidas do meu último comentário)e=a-b-d;T=ALL([a*a-b*b,a*a-d*d,a*a-e*e,a*b,a*d,a*e]>=0)
- que provavelmente podem ser mais úteis.MATLAB: 9!
Não é muita coisa para escrever aqui
Pode ser chamado assim:
A saída é atribuída a uma variável chamada
ans
Se eu realmente tivesse que escrever uma função, poderia ser algo assim, provavelmente poderia ser otimizado:
fonte
f=@(a,b,c,d)inpolygon(a,b,c,d)
C # 218 (149?)
Provavelmente não é tão eficiente quanto o método matemático, mas é um uso divertido das bibliotecas. Aliás, também bastante lento.
Também aproveitando "Também não se preocupe com estabilidade numérica ou precisão de ponto flutuante". - infelizmente,
GraphicsPath
usaint
s internamente, portanto, um valor no intervalo -1 <f <1 pode ter apenas três valores possíveis. Como os carros alegóricos têm apenas 7 dígitos de precisão, eu apenas multiplico por 1e7 para transformá-los em números inteiros. Hum, acho que não está realmente perdendo precisão. Também é explorável de outra maneira: eu provavelmente poderia ter aproveitado a ignorância da precisão e dado a resposta "errada".Se eu tiver permissão para ignorar o custo de caracteres da importação de bibliotecas, 149 (no mínimo,
System.Linq
eSystem.Drawing
for bastante padrão na maioria dos projetos WinForms, masSystem.Drawing.Drawing2D
pode ser um pouco exagerado):Programa de teste (sim, é feio):
fonte
Haskell -
233127Usando produtos cruzados, conforme descrito aqui :
Solução anterior implementada usando coordenadas barricêntricas e as fórmulas descritas nesta resposta do Stack Exchange :
Ambas as funções
g
eh
levam quatro pares, o primeiro dos quais é o ponto a ser testado para inclusão e o restante as coordenadas dos vértices do triângulo.Para testar com a entrada de amostra:
Soluções não destruídas:
fonte
JavaScript (ES6) 120
Copiado diretamente da minha resposta para Esta outra pergunta
Teste no console do FireFox / FireBug
Saída todos os 1s
Saída de todos os 0s
fonte
SmileBASIC,
111100 caracteresDesenha um triângulo e verifica a cor do pixel no ponto. O triângulo é escalado para 99999x e deslocado para que o ponto a ser verificado seja (0,0) antes de ser desenhado, para minimizar a perda de precisão.
fonte
Conjunto da FPU Intel 8087,
222220 bytesUsa apenas o hardware da FPU 8087 para calcular. Aqui está a versão desmontada (também desmontada neste caso) como um MACRO (você poupará os códigos de 220 bytes hexadecimais):
Explicação
Usa o determinado para calcular a área do triângulo ABC e, em seguida, o triângulo formado com o ponto X e dois outros pontos do triângulo ABC. Se a área do triângulo ABC for igual à soma das áreas dos triângulos XBC + AXC + ABX, o ponto estará dentro do triângulo. O resultado é retornado como ZF.
O que há de bom nisso
Todas as operações matemáticas e de ponto flutuante são feitas em hardware com precisão estendida de 80 bits. A comparação final do ponto flutuante também é feita no hardware, por isso será muito precisa.
Isso também usa todos os oito registros de pilha do 8087 de uma só vez.
O que não é tão legal nisso
Como os pontos do triângulo devem ser reconectados às fórmulas várias vezes durante o cálculo, é necessário que cada variável na memória seja carregada na pilha da FPU, registrando uma de cada vez na ordem correta. Embora isso possa ser facilmente modelado como uma função como um MACRO, significa que o código é expandido todas as vezes na montagem, criando código redundante. 41 bytes foram salvos movendo alguns dos mesmos segmentos de código repetido para PROCs. No entanto, ele torna o código menos legível, portanto, a lista acima é sem ele (e é por isso que é rotulado como "não destruído").
Testes
Aqui está um programa de teste usando o IBM DOS mostrando a saída:
Saída
fonte
C 414 (era 465)
Golfe
Declaração de função original adicionada para explicação
Reescrita como uma função nomeada: insira via stdin uma cada linha ou todas em uma linha separada por espaço.
fonte
double
redefiniu comoD
mas ainda o usadouble
no código.Java, 149 caracteres
Horrível, considerando que tenho que escrever "Matemática". toda vez. Este é o programa atual:
onde a é o x do ponto a, b é o x do ponto b, c para x de c, d é y de a, e é y de b, f é o y de c, e x e y são x e y do ponto. O booleano k determina se é verdadeiro ou não.
fonte
100*
?JavaScript 125/198
Se pontos são fornecidos em 8 argumentos:
Se pontos são fornecidos em uma matriz bidimensional:
Esse código não usa nenhuma dessas matemáticas vetoriais sofisticadas. Em vez disso, ele usa apenas um truque simples de álgebra para determinar se o ponto está dentro do triângulo ou não. A fórmula:
que indica o ponto em que lado de uma linha é derivado de reorganizar a definição de inclinação:
Se testarmos todos os três lados, todos os três deverão produzir alguns números com o mesmo sinal somente quando o ponto estiver dentro do triângulo, pois estamos testando-o em torno do triângulo. Se o ponto estiver do lado, um dos testes retornará 0.
código de teste jsFiddle: http://jsfiddle.net/DerekL/zEzZU/
97 caracteres (sem contar espaços ou tabulações) contam se convertidos em CoffeeScript:
115 caracteres se convertidos em ES6:
fonte
d=(x,y,...)=>{...}
. No seu caso, você pode economizar ainda mais usando o CoffeeScript, o que não é necessárioreturn
: pastebin.com/RVFk1D5k ... e, em qualquer caso, você pode salvar um byte usando em<1
vez de==0
.R, 23
Inspirado pelo MATLAB ,
chamado como
SDMTools::pnt.in.poly(point,triangle)
wherepoint
é um vetor de comprimento 2 etriangle
é uma matriz de vértices 3x2. SDMTools está disponível no CRAN.fonte
Mathematica, 38 caracteres
Exemplo:
(* Verdade *)
fonte
C (gcc) , 108 bytes
Experimente online!
Leva três produtos cruzados e retorna
1
se o sinal dok̂
componente não mudar.fonte