Verifique se o ponto está dentro do triângulo

40

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/ 0ou 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 Truee 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)]
xnor
fonte
Qual é a sua definição de personagem? Ascii? Codificável em 7 bits? Em um byte? Algum Unicode?
Isaacg
O que você sugere? Já existem soluções que usam código compactado.
Xnor
Normalmente, acredito que os bytes sejam usados ​​para caracteres não-Ascii, porque, caso contrário, a vantagem do Utf-32 é insuperável.
Isaacg
Bem, não posso voltar agora; qualquer caractere Unicode é um caractere. Comprima se quiser.
Xnor

Respostas:

19

Javascript / ECMAScript 6, 161 159 158/152

Javascript:

function $(t,r,i,a,n,g,l,e){b=(-g*l+a*(-n+l)+i*(g-e)+n*e)/2;c=b<0?-1:1;d=(a*l-i*e+(e-a)*t+(i-l)*r)*c;f=(i*g-a*n+(a-g)*t+(n-i)*r)*c;return d>0&&f>0&&d+f<2*b*c}

Versão ECMAScript 6 (obrigado m.buettner, salva 6 caracteres)

$=(t,r,i,a,n,g,l,e)=>{b=(-g*l+a*(-n+l)+i*(g-e)+n*e)/2;c=b<0?-1:1;d=(a*l-i*e+(e-a)*t+(i-l)*r)*c;f=(i*g-a*n+(a-g)*t+(n-i)*r)*c;return d>0&&f>0&&d+f<2*b*c}

Chame como tal (retorna trueou false):

$(pointX, pointY, v1X, v1Y, v2X, v2Y, v3X, v3Y);

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:

function $ (pointX, pointY, v1X, v1Y, v2X, v2Y, v3X, v3Y) {
  var A =  (-v2Y * v3X + v1Y * (-v2X + v3X) + v1X * (v2Y - v3Y) + v2X * v3Y) / 2;
  var sign = A < 0 ? -1 : 1;
  var s = (v1Y * v3X - v1X * v3Y + (v3Y - v1Y) * pointX + (v1X - v3X) * pointY) * sign;
  var t = (v1X * v2Y - v1Y * v2X + (v1Y - v2Y) * pointX + (v2X - v1X) * pointY) * sign;
  return s > 0 && t > 0 && s + t < 2 * A * sign;
}
Abraão
fonte
12
+1, se apenas para os nomes dos parâmetros!
Matt
Por que você precisa interromper meu UserScript com contagem de caracteres ???
precisa saber é o seguinte
@ kitcar2000, o que você quer dizer?
Abra Abraham
As regras dizem que os caracteres são contados, não bytes. Portanto, você pode usar o seguinte: xem.github.io/obfuscatweet para caber em 122 caracteres
xem
11
Estou enganado, ou você poderia ter usado em (a*(l-n)+i*(g-e)+n*e-g*l)vez de (-g*l+a*(-n+l)+i*(g-e)+n*e)?
Zachary
19

Python 2.7 128 127 117 110 109 103 99 95 94 91 90

Minha primeira tentativa de código-golfe!

Código

f=lambda x,y,t:sum(a*y+c*b+d*x<d*a+c*y+b*x for i in(0,1,2)for a,b,c,d in[t[i-1]+t[i]])%3<1

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

| 1 x1 y1 |      | 1 x2 y2 |      | 1 x3 y3 |
| 1 x2 y2 | ,    | 1 x3 y3 | ,    | 1 x1 y1 | .
| 1 x  y  |      | 1 x  y  |      | 1 x  y  |

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==3e False+False+False==0para determinar se todos esses determinantes têm o mesmo sinal.

Uso os índices de lista negativa do Python usando em t[-1]vez de t[(i+1)%3].

Obrigado Peter pela idéia de usar em s%3<1vez de s 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:

f=lambda p,t,o=[1]:sum([det(Matrix([o+t[i-1],o+t[i],o+p]))<0for i in 0,1,2])%3<1

onde p=[x,y]et=[[x1,y1],[x2,y2],[x3,y3]]

Alex L
fonte
11
Pode s in (0,3)ser reduzido para s%3<1?
Peter Taylor
11
O uso de índices negativos pode ser ajustado para salvar mais uma: -1,0,1 ... t[i]+t[i+1]é equivalente a0,1,2 ... t[i-1]+t[i]
Peter Taylor
@PeterTaylor Absolutamente certo! Pena que eu removi o espaço in -1,0,1antes de ler isso. Na verdade, seu caminho é mais legível, então eu o usarei de qualquer maneira.
Alex L
11
Bem-vindo ao código de golfe! Você pode se livrar dos colchetes para a compreensão da lista dentro do sumse colocar 0,1,2entre 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 o 1,2,3confundem porque ele tenta analisá-las como argumentos separados.
Xnor
16

Mathematica, 67 bytes

f=Equal@@({#2,-#}&@@(#-#2).(x-#)>0&@@@Partition[x=#;#2,2,1,{1,1}])&

A função usa dois argumentos, o ponto Xe uma lista de pontos {A,B,C}, que são referidos como #e #2respectivamente. Ou seja, se você ligar

f[X,{A,B,C}]

então você terá #como Xe #2como {A,B,C}. (Observe que existem duas outras funções anônimas aninhadas dentro do código - #e #2têm um significado diferente dentro delas).

Aqui está uma explicação da própria função:

                                              x=#;#2            & (* Save X into a variable x, but evaluate to {A,B,C}. *)
                                    Partition[x=#;#2,2,1,{1,1}] & (* Get a cyclic list of pairs {{A,B},{B,C},{C,B}}. *)
       (                        &@@@Partition[x=#;#2,2,1,{1,1}])& (* Define an anonymous function and apply it to each 
                                                                     of the above pairs. The two elements are referred 
                                                                     to as # and #2. *)
       (          (#-#2)        &@@@Partition[x=#;#2,2,1,{1,1}])& (* Subtract the two points. For a pair of vertices 
                                                                     this yields a vector corresponding to the edge 
                                                                     between them. *)
        {#2,-#}&                                                  (* An anonymous function that takes two values, 
                                                                     reverses them, inverts the sign of one of them 
                                                                     and puts them into a list. *)
       ({#2,-#}&@@(#-#2)        &@@@Partition[x=#;#2,2,1,{1,1}])& (* Applied to the edge, this yields its normal. *)
       ({#2,-#}&@@(#-#2).(x-#)  &@@@Partition[x=#;#2,2,1,{1,1}])& (* Take the scalar product of that normal with a
                                                                     vector from a vertex to x. This is projection of 
                                                                     this vector onto that normal and hence the SIGNED
                                                                     distance of x from the edge. *)
       ({#2,-#}&@@(#-#2).(x-#)>0&@@@Partition[x=#;#2,2,1,{1,1}])& (* Check the sign of that distance, the exact mapping 
                                                                     between (left, right) and (True, False) is 
                                                                     irrelevant, as long as it's consistent. *)
Equal@@({#2,-#}&@@(#-#2).(x-#)>0&@@@Partition[x=#;#2,2,1,{1,1}])& (* Check if all signs are equal - that is, if point X 
                                                                     lies on the same side of all edges. This is 
                                                                     equivalent to check that the point is inside the 
                                                                     triangle. *)

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.

Martin Ender
fonte
Não seria mais eficiente verificar se o produto das distâncias é positivo do que se todos os sinais são iguais? Não conheço o Mathematica, mas parece que deveria ser mais fácil.
Isaacg 3/07
@isaacg Existem três termos, portanto, se todos forem negativos, o produto será negativo e, se todos forem positivos, o produto será positivo. Sua abordagem só funciona se os sinais de dois números forem iguais.
Martin Ender
Por que não usar Det?
Alephalpha
@alephalpha Bem, provavelmente porque eu não pensei nisso. : P ... Vou olhar para isso
Martin Ender
@alephalpha Hum, não, não consigo encontrar uma maneira agora de construir as três matrizes necessárias em menos caracteres.
Martin Ender
7

CJam, 66 63 59 52 46 34 32 31 30 28 caracteres

"Ă䒟损崙㩴ァ椟饃꿾藭鑭蘁"2G#b131b:c~

Depois de transformar a cadeia Unicode, o seguinte código ( 33 bytes ) é avaliado:

{2*2/\f{f{+~@-@@-}~@@*@@*>})-!}:T

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

$ cat triangle.cjam
"Ă䒟损崙㩴ァ椟饃꿾藭鑭蘁"2G#b131b:c~

[
  [-0.31961 -0.12646] [ [0.38478 0.37419]   [-0.30613 -0.59754] [-0.85548 0.6633]   ] T
  [-0.87427 -0.00831] [ [0.78829 0.60409]   [-0.90904 -0.13856] [-0.80685 0.48468]  ] T
  [0.28997 -0.03668]  [ [-0.28362 0.42831]  [0.39332 -0.07474]  [-0.48694 -0.10497] ] T
  [-0.07783 0.04415]  [ [-0.34355 -0.07161] [0.59105 -0.93145]  [0.29402 0.90334]   ] T
  [0.36107 0.05389]   [ [0.27103 0.47754]   [-0.00341 -0.79472] [0.82549 -0.29028]  ] T
  [-0.01655 -0.20437] [ [-0.36194 -0.90281] [-0.26515 -0.4172]  [0.36181 0.51683]   ] T
  [-0.12198 -0.45897] [ [-0.35128 -0.85405] [0.84566 0.99364]   [0.13767 0.78618]   ] T
  [-0.03847 -0.81531] [ [-0.18704 -0.33282] [-0.95717 -0.6337]  [0.10976 -0.88374]  ] T
  [0.07904 -0.06245]  [ [0.95181 -0.84223]  [-0.75583 -0.34406] [0.16785 0.87519]   ] T
  [-0.33485 0.53875]  [ [-0.25173 0.51317]  [-0.62441 -0.90698] [-0.47925 0.74832]  ] T
  [-0.99103 0.43842]  [ [0.78128 -0.10985]  [-0.84714 -0.20558] [-0.08925 -0.78608] ] T
  [0.15087 -0.56212]  [ [-0.87374 -0.3787]  [0.86403 0.60374]   [0.01392 0.84362]   ] T
  [0.1114 0.66496]    [ [-0.92633 0.27408]  [0.92439 0.43692]   [0.8298 -0.29647]   ] T
  [0.87786 -0.8594]   [ [-0.42283 -0.97999] [0.58659 -0.327]    [-0.22656 0.80896]  ] T
  [0.43525 -0.8923]   [ [0.86119 0.78278]   [-0.01348 0.98093]  [-0.56244 -0.75129] ] T
  [-0.73365 0.28332]  [ [0.63263 0.17177]   [-0.38398 -0.43497] [-0.31123 0.73168]  ] T
  [-0.57694 -0.87713] [ [-0.93622 0.89397]  [0.93117 0.40775]   [0.2323 -0.30718]   ] T
  [0.91059 0.75966]   [ [0.60118 0.73186]   [0.32178 0.88296]   [-0.90087 -0.26367] ] T
  [0.3463 -0.89397]   [ [0.99108 0.13557]   [0.50122 -0.8724]   [0.43385 0.00167]   ] T
  [0.88121 0.36469]   [ [-0.29829 0.21429]  [0.31395 0.2734]    [0.43267 -0.78192]  ] T
]p;

$ cjam triangle.cjam
[1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0]
Dennis
fonte
Essa é uma função nomeada?
Martin Ender
@ m.buettner: Mais ou menos. O wiki oficial diz o seguinte: Block - uma seção de programa delimitado por {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).
Dennis
11
@xnor 1m<@m*prepara 3 pares de X e o próximo ( i+1th) vértice do triângulo. @-@@-move o ( iv) 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 retorna 1se 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.
precisa saber é o seguinte
11
37 bytes: {[_1m<\]z\f{f{+~@-@@-}~@@*@@*>})-!}:T. Use 2m>ou Wm<para segurança Unicode.
21714
11
33 bytes:{2*2/\f{f{+~@-@@-}~@@*@@*>})-!}:T
jimmy23013
5

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!

int f(float*X,float*Y,float x,float y){int i,j,c=0;for(i=0,j=2;i<3;j=i++)if(((Y[i]>y)!=(Y[j]>y))&&(x<(X[j]-X[i])*(y-Y[i])/(Y[j]-Y[i])+X[i]))c=!c;return c;}

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 javascript
bebe
@ beeb - Isso causa um erro de sintaxe.
Derek朕會功夫
Isso não causa um erro de sintaxe.
bebe
4

Pitão 1.0.5 , 57 54 51

DgYb=Z0J'bWbK;bDiHNR*-'H'K-@N1@K1~Z>iYJiJY=JK)R!%Z3

Define a função g, que recebe duas entradas: o ponto de teste e, em seguida, a lista dos vértices do triângulo. SaídasTrue e False. Nota: Destrói a entrada, especificamente b, a lista dos vértices do triângulo.

Tente aqui . Os últimos caracteres gvwvwchamam a função com um caso de teste nas próximas duas linhas.

Baseado em neste algoritmo

Explicação:

DgYb                  Define g(Y,b):
=Z0                     Z=0
J'b                     J=b[0]              (No = is needed because j is special).
Wb                      While len(b)>0:     (While b:)
K;b                       K=b.pop()
DiHN                      Define i(H,N):    
R*-'H'K-@N1@K1              Return half of the linked equation.
~ZiYJiJY                  Z+=i(Y,J)>i(J,Y)
=JK                       J=K
)                       Wend
R!%Z3                   return not Z%3==0   (True iff Z == 0 or 3)

A guerra CJam - Pyth continua!

isaacg
fonte
Essa deve ser uma função nomeada. Está wrecebendo entrada STDIN?
Xnor
@ xnor Opa, eu perdi essa parte da descrição. Irá editar.
Isaacg
@xnor As funções que imprimem a resposta são permitidas ou devem retornar a resposta? Atualmente, isso imprime a resposta, mas eu poderia devolvê-lo para mais um personagem.
Isaacg
Retorne a resposta.
Xnor
Você pode salvar caracteres substituindo o contador Zpor um conjunto vazio com o qual você acumula Z|=e testar seu comprimento para ver se são apenas 0ou 1foram vistos? A estratégia ficou mais longa em Python, mas talvez valha a pena usar as primitivas de Pyth.
Xnor
4

J 64 45 (42 sem atribuição)

c=:*./@(>:&0)@({.(,(1-+/))@%.|:@}.)@(}:-"1{:)

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

NB. example in triangle
D =: 4 2 $ 1 1 0 0 3 0 0 2 NB. 4 rows , x first, then the vertices of the triangle

NB. subtract last vertex coordinates from the rest and drop reference node
n=: (}:-"1{:)

NB. preprocessed to barycentric coordinates
bar=: {. (, 1 - +/)@%. |:@}.

NB. all positive
ap =: *./@(>:&0)

insided =: ap@bar@n

inside D
1

Uma execução nos exemplos fornecidos:

   true =: 0 : 0
[(-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 =: 0 : 0
[(-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)]
)
   NB. replace - by _ to avoid problems
   NB. cut up per row, drop the [ ] and convert to numbers
   $dat_t =: ((4 2 $ ".)@}:@}.;._2) (true='-')} true ,: '_'
10 4 2
   $dat_f =: ((4 2 $ ".)@}:@}.;._2) (false='-')}false,: '_'
10 4 2
   NB. this results in arrays with shape 10 4 2

   NB. for each 4 x 2 array (rank 2), do c for all true instances
   c=:*./@(>:&0)@({.(,(1-+/))@%.|:@}.)@(}:-"1{:)
   c"2 dat_t
1 1 1 1 1 1 1 1 1 1
   NB. the same for the false ones, demonstrating anonymous usage
   NB. still a function though (or verb in J parlance)
   *./@(>:&0)@({.(,(1-+/))@%.|:@}.)@(}:-"1{:)"2 dat_f
0 0 0 0 0 0 0 0 0 0
jpjacobs
fonte
Eu pedi uma função nomeada, para que os caracteres de atribuição sejam contados. Aqui estão alguns pontos para generalizar para polígonos! ······
xnor
Bem, na verdade, não generalizo bastante para polígonos, mas sim para simplexes N-dimensionais, com N+1vé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 que N+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)
jpjacobs
4

Caracteres HTML5 + JS, 13b + 146b / 141b / 114

HTML:

<canvas id=C>

JS (146b):

// @params: t1x, t1y, t2x, t2y, t3x, t3y, pointx, pointy
function T(a,b,c,d,e,f,g,h){with(C.getContext("2d"))return beginPath(),moveTo(a,b),lineTo(c,d),lineTo(e,f),fill(),!!getImageData(g,h,1,1).data[3]}

ou ES6 (141b):

T=(a,b,c,d,e,f,g,h)=>{with(C.getContext("2d"))return beginPath(),moveTo(a,b),lineTo(c,d),lineTo(e,f),fill(),!!getImageData(g,h,1,1).data[3]}

ou ES6 ofuscado por unicode (114 caracteres):

eval(unescape(escape('𥀽𚁡𛁢𛁣𛁤𛁥𛁦𛁧𛁨𚐽🡻𭱩𭁨𚁃𛡧𩑴𠱯𫡴𩑸𭀨𘠲𩀢𚐩𬡥𭁵𬡮𘁢𩑧𪑮𤁡𭁨𚀩𛁭𫱶𩑔𫰨𨐬𨠩𛁬𪑮𩑔𫰨𨰬𩀩𛁬𪑮𩑔𫰨𩐬𩠩𛁦𪑬𫀨𚐬𘐡𩱥𭁉𫑡𩱥𡁡𭁡𚁧𛁨𛀱𛀱𚐮𩁡𭁡𦰳𧑽').replace(/uD./g,'')))

demo: http://jsfiddle.net/xH8mV/

Ofuscação Unicode feita com: http://xem.github.io/obfuscatweet/

xem
fonte
Parece que não produz o resultado correto quando o ponto está próximo: jsfiddle.net/L2B2A Acredito que seja porque todas as entradas estão entre (-1,1) e seu código está apenas testando os 4 pixels ao redor a origem.
Derek朕會功夫
é isso mesmo, para encaixar nos exemplos, devo alterar a origem e a escala da minha tela para lidar com triângulos internos [-1,1]. Mas por que esses triângulos são tão pequenos assim?
Xem
o problema diz que todos os xy estão entre -1 e 1. Não sei realmente o porquê, mas acredito que você pode multiplicar cada entrada por 1e7 (para manter a precisão) e obter o resultado correto: D
Derek 朕 會 會
Uma solução gráfica, muito inteligente!
Xnor
3

Python (65)

As pessoas parecem ter terminado de enviar, então postarei minha própria solução na minha pergunta.

f=lambda X,L:sum(((L[i-1]-X)/(L[i]-X)).imag>0for i in(0,1,2))%3<1

Xé o número complexo que representa os pontos de teste e Lé uma lista de três pontos, cada um um número complexo.

Primeiro, explicarei uma versão menos golfe do código;

def f(X,A,B,C):A-=X;B-=X;C-=X;return((A/B).imag>0)==((B/C).imag>0)==((C/A).imag>0)

Mudamos os pontos A,B,C,Xpara que Xestejam na origem, aproveitando a aritmética complexa interna do Python. Precisamos verificar se a origem está contida no casco convexo de A,B,C. Isso é equivalente à origem sempre no mesmo lado (esquerdo ou direito) dos segmentos de linha AB, BC e AC.

Um segmento ABtem 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 ângulos a, be ccorrespondentes a esses pontos, isso significa b-a < 180 degrees(ângulos tomados no intervalo de 0 a 360 graus). Como números complexos angle(B/A)=angle(B)/angle(A),. Além disso, angle(x) < 180 degreesexatamente para apontar no meio plano superior, que verificamos via imag(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íclico A,B,Cindica se o triângulo ABCcontém a origem.

Agora, voltemos ao código totalmente golfado

f=lambda X,L:sum(((L[i-1]-X)/(L[i]-X)).imag>0for i in(0,1,2))%3<1

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 todos True( 1) ou todos False( 0), nós os adicionamos e verificamos a divisibilidade em 3, como muitas soluções.

xnor
fonte
2

Fortran - 232 218 195 174

Horrível. A função é horrível devido ao requisito de que os dados sejam passados ​​para ela e não podemos pré-processá-los.

logical function L(x);real::x(8);p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3);s=x(6)-x(4);t=x(7)-x(3);u=x(8)-x(4);L=ALL([p*(s-u)+q*(t-r)+r*u-t*s,p*u-q*t,q*r-p*s]>=r*u-t*s);endfunction

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 é

program inTriagle
   real, dimension(2) :: a,b,c,x
   do 
      print*,"Enter coordinates as x,a,b,c"
      read*,x,a,b,c
      if(all(x==0.0).and.all(a==0.0).and.all(b==0.0).and.all(c==0.0)) exit
      print*,"Is point in triangle: ",T(x,a,b,c)
   enddo
 contains!                       
   logical function L(x)
     real::x(8)
     p=x(1)-x(3);q=x(2)-x(4);r=x(5)-x(3)
     s=x(6)-x(4);t=x(7)-x(3);u=x(8)-x(4)
     L=ALL([p*(s-u)+q*(t-r)+r*u-t*s,p*u-q*t,q*r-p*s]>=r*u-t*s)
   endfunction
end program inTriagle
Kyle Kanos
fonte
11
Você pode reduzir um pouco isso confiando na digitação implícita do Fortran e usando uma única matriz de entrada contendo todos os 8 números: 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);endtentei abreviá-lo ainda mais usando operações de lista, mas infelizmente isso não funcionou muito bem.
Ventero
11
Ainda mais curto, eliminando subexpressões mais comuns: 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);endespero 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.
Ventero 03/07
@Ventero: Eu não posso acreditar que eu esqueci de abusar digitação implícita :( Obrigado por sua ajuda.!
Kyle Kanos
@ Ventero: Além disso, parece que a minha resposta depende da orientação do triângulo. O primeiro Trueexemplo no OP dá Falsese eu trocar Be Cvalores 's, enquanto dando Truepara a orientação original.
Kyle Kanos
Ah, de fato, o problema é causado quando (reutilizando a notação do meu comentário anterior) a < 0, que inverte efetivamente a condição que você precisa testar. Infelizmente, isso não pode ser corrigido apenas envolvendo tudo em um abs, como então a condição implícita be do mesmo sinal de ase 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.
Ventero 04/07/2014
2

MATLAB: 9!

Não é muita coisa para escrever aqui

inpolygon

Pode ser chamado assim:

inpolygon(2/3, 2/3, [0 1 1], [0 0 1])

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:

function y=f(a,b,c,d)
inpolygon(a,b,c,d)
Dennis Jaheruddin
fonte
2
pode ser mais curto usando um identificador de função:f=@(a,b,c,d)inpolygon(a,b,c,d)
jpjacobs
2

C # 218 (149?)

using P=System.Drawing.PointF;
bool F(P[]p){for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}P[]a=new P[3];Array.Copy(p,1,a,0,3);var g=new System.Drawing.Drawing2D.GraphicsPath();g.AddLines(a);return g.IsVisible(p[0]);}

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, GraphicsPathusa ints 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.Linqe System.Drawingfor bastante padrão na maioria dos projetos WinForms, mas System.Drawing.Drawing2Dpode ser um pouco exagerado):

bool G(PointF[]p){for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}var g=new GraphicsPath();g.AddLines(p.Skip(1).ToArray());return g.IsVisible(p[0]);}

Programa de teste (sim, é feio):

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using P=System.Drawing.PointF;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        Program prog = new Program();
        foreach (string test in
@"[(-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)]
[(-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)]".Split('\n'))
        {
            string t = test.Replace("[(", "").Replace(")]", "");
            string[] points = t.Split(new string[] { "), (" }, StringSplitOptions.None);

            string[] p = points[0].Split(',');
            P[] xabc = new P[4];

            for (int i = 0; i < 4; i++)
            {
                p = points[i].Split(',');
                xabc[i] = new F(float.Parse(p[0]), float.Parse(p[1]));
            }

            Console.WriteLine(test + "=>" + prog.F(xabc));
        }

        Console.ReadKey();
    }

    bool G(PointF[]p)
    {
        for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}
        var g=new GraphicsPath();
        g.AddLines(p.Skip(1).ToArray());
        return g.IsVisible(p[0]);
    }

    bool F(P[]p)
    {
        for(int i=0;i<4;i++){p[i].X*=1e7f;p[i].Y*=1e7f;}
        var g=new System.Drawing.Drawing2D.GraphicsPath();
        g.AddLines(p.Skip(1).ToArray());
        return g.IsVisible(p[0]);
    }
}
Prumo
fonte
Bonito, fazer com que o mecanismo de desenho faça o trabalho.
Xnor
2

Haskell - 233 127

Usando produtos cruzados, conforme descrito aqui :

h(a,b)(p,q)(r,s)(t,u)=z a b p q r s==z a b r s t u&&z a b r s t u==z a b t u p q where z j k l m n o =(o-m)*(j-l)+(l-n)*(k-m)>0

Solução anterior implementada usando coordenadas barricêntricas e as fórmulas descritas nesta resposta do Stack Exchange :

g(p,q)(r,s)(t,u)(v,w)=
 let (j,k)=(p+(-r),q+(-s))
     (l,m)=(t+(-r),u+(-s))
     (n,o)=(v+(-r),w+(-s))
     d=l*o-n*m
     a=(j*(m-o)+k*(n-l)+l*o-n*m)/d
     b=(j*o-k*n)/d
     c=(k*l-j*m)/d
 in (0<=a&&a<1)&&(0<=b&&b<1)&&(0<=c&&c<1)

Ambas as funções ge hlevam 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:

let trueTestCases =
  [((-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))]

let falseTestCases =
  [((-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))]

type Point = (Double, Double)

test :: [(Point, Point, Point, Point)] -> [Bool]
test testCases =
  map (\((px,py),(ax,ay),(bx,by),(cx,cy)) -> h (px,py) (ax,ay) (bx,by) (cx,cy)) testCases

test trueTestCases --> [True,True,True,True,True,True,True,True,True,True]
test falseTestCases --> [False,False,False,False,False,False,False,False,False,False]

Soluções não destruídas:

type Point = (Double, Double)

-- using cross products

triangulate' (a, b) (p, q) (r, s) (t, u) =
  (side a b p q r s == side a b r s t u) && (side a b r s t u == side a b t u p q)
  where side j k l m n o = (o - m) * (j - l) + (-n + l) * (k - m) >= 0

-- using barycentric coordinates

triangulate :: (Point, Point, Point, Point) -> Bool
triangulate ((px, py), (ax, ay), (bx, by), (cx, cy)) = 
  let (p'x, p'y) = (px + (-ax), py + (-ay))
      (b'x, b'y) = (bx + (-ax), by + (-ay))
      (c'x, c'y) = (cx + (-ax), cy + (-ay))
      d = b'x * c'y - c'x * b'y
      a = (p'x * (b'y - c'y) + p'y * (c'x - b'x) + b'x * c'y - c'x * b'y) / d
      b = (p'x * c'y - p'y * c'x) / d
      c = (p'y * b'x - p'x * b'y) / d
  in
      (0 <= a && a < 1) && (0 <= b && b < 1) && (0 <= c && c < 1)
OI
fonte
2

JavaScript (ES6) 120

C=(p,q,i,j,k,l,m,n,
 z=j*(m-k)+i*(l-n)+k*n-l*m,
 s=(j*m-i*n+(n-j)*p+(i-m)*q)/z,
 t=(i*l-j*k+(j-l)*p+(k-i)*q)/z
)=>s>0&t>0&s+t<1

Copiado diretamente da minha resposta para Esta outra pergunta

Teste no console do FireFox / FireBug

Saída todos os 1s

;[
C(-0.31961, -0.12646, 0.38478, 0.37419, -0.30613, -0.59754, -0.85548, 0.6633),
C(-0.87427, -0.00831, 0.78829, 0.60409, -0.90904, -0.13856, -0.80685, 0.48468),
C(0.28997, -0.03668, -0.28362, 0.42831, 0.39332, -0.07474, -0.48694, -0.10497),
C(-0.07783, 0.04415, -0.34355, -0.07161, 0.59105, -0.93145, 0.29402, 0.90334),
C(0.36107, 0.05389, 0.27103, 0.47754, -0.00341, -0.79472, 0.82549, -0.29028),
C(-0.01655, -0.20437, -0.36194, -0.90281, -0.26515, -0.4172, 0.36181, 0.51683),
C(-0.12198, -0.45897, -0.35128, -0.85405, 0.84566, 0.99364, 0.13767, 0.78618),
C(-0.03847, -0.81531, -0.18704, -0.33282, -0.95717, -0.6337, 0.10976, -0.88374),
C(0.07904, -0.06245, 0.95181, -0.84223, -0.75583, -0.34406, 0.16785, 0.87519),
C(-0.33485, 0.53875, -0.25173, 0.51317, -0.62441, -0.90698, -0.47925, 0.74832)
]

Saída de todos os 0s

;[
C(-0.99103, 0.43842,0.78128, -0.10985,-0.84714, -0.20558,-0.08925, -0.78608),
C(0.15087, -0.56212,-0.87374, -0.3787,0.86403, 0.60374,0.01392, 0.84362),
C(0.1114, 0.66496,-0.92633, 0.27408,0.92439, 0.43692,0.8298, -0.29647),
C(0.87786, -0.8594,-0.42283, -0.97999,0.58659, -0.327,-0.22656, 0.80896),
C(0.43525, -0.8923,0.86119, 0.78278,-0.01348, 0.98093,-0.56244, -0.75129),
C(-0.73365, 0.28332,0.63263, 0.17177,-0.38398, -0.43497,-0.31123, 0.73168),
C(-0.57694, -0.87713,-0.93622, 0.89397,0.93117, 0.40775,0.2323, -0.30718),
C(0.91059, 0.75966,0.60118, 0.73186,0.32178, 0.88296,-0.90087, -0.26367),
C(0.3463, -0.89397,0.99108, 0.13557,0.50122, -0.8724,0.43385, 0.00167),
C(0.88121, 0.36469,-0.29829, 0.21429,0.31395, 0.2734,0.43267, -0.78192)
]
edc65
fonte
2

SmileBASIC, 111 100 caracteres

DEF T X,Y,A,B,C,D,E,F
Q=9e5GCLS
GTRI(A-X)*Q,Q*(B-Y),Q*(C-X),Q*(D-Y),Q*(E-X),Q*(F-Y)?!!GSPOIT(0,0)END

Desenha 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.

12Me21
fonte
2

Conjunto da FPU Intel 8087, 222 220 bytes

Usa 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):

; calculate the area of of a triangle ABC using determinate
; input: coordinates (float), Ax,Ay,Bx,By,Cx,Cy
; output: area in ST
TAREA   MACRO   A1,A2,B1,B2,C1,C2
    FLD  A1
    FLD  B2
    FLD  C2
    FSUB        ; ST = By - Cy
    FMUL        ; ST = Ax * ( By - Cy )
    FLD  B1 
    FLD  C2
    FLD  A2
    FSUB        ; ST = Cy - Ay
    FMUL        ; ST = Bx * ( Cy - Ay )
    FLD  C1
    FLD  A2
    FLD  B2
    FSUB        ; Ay - By
    FMUL        ; Cx * ( Ay - By )
    FADD        ; Cx * ( Ay - By ) + Bx * ( Cy - Ay )
    FADD        ; Cx * ( Ay - By ) + Bx * ( Cy - Ay ) + Ax * ( By - Cy )
    FLD1        ; make a value of 2
    FADD ST,ST  ; ST = 2
    FDIV        ; divide by 2
    FABS        ; take abs value
        ENDM

; determine if point X is in triangle ABC
; input: points X, A, B, C
; output: ZF=1 if X in triangle, ZF=0 if X not in triangle
TXINABC     MACRO X1,X2,A1,A2,B1,B2,C1,C2

    TAREA  A1,A2,B1,B2,C1,C2    ; ST(3) = area of triangle ABC
    TAREA  X1,X2,B1,B2,C1,C2    ; ST(2) = area of triangle XBC
    TAREA  A1,A2,X1,X2,C1,C2    ; ST(1) = area of triangle AXC
    TAREA  A1,A2,B1,B2,X1,X2    ; ST(0) = area of triangle ABX

    FADD        ; add areas of triangles with point
    FADD        ; ST = ST + ST(1) + ST(2)
    FCOMPP      ; compare ST to ST(1) and pop results
    FWAIT       ; sync CPU/FPU
    FSTSW R     ; store result flags to R
    MOV  AX, R  ; move result to AX
    SAHF        ; store result into CPU flags for conditional check
        ENDM

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:

TTEST   MACRO T
        LOCAL IS_IN_TRI

    TXINABC T,T+4*1,T+4*2,T+4*3,T+4*4,T+4*5,T+4*6,T+4*7
    MOV  DX, OFFSET TEQ     ; load true string by default 
    JZ   IS_IN_TRI          ; if ZF=1, it is in triangle, skip to display
    MOV  DX, OFFSET FEQ     ; otherwise ZF=0 means not in triangle, so load false string
IS_IN_TRI:
    MOV  AH, 9              ; DOS write string function
    INT  21H 
        ENDM

START:
    FINIT                   ; reset 8087

    TTEST   T0              ; true tests
    TTEST   T1
    TTEST   T2
    TTEST   T3
    TTEST   T4
    TTEST   T5
    TTEST   T6
    TTEST   T7
    TTEST   T8
    TTEST   T9

    TTEST   F0              ; false tests
    TTEST   F1
    TTEST   F2
    TTEST   F3
    TTEST   F4
    TTEST   F5
    TTEST   F6  
    TTEST   F7
    TTEST   F8  
    TTEST   F9

    RET         ; return to DOS

T0  DD  -0.31961, -0.12646, 0.38478, 0.37419, -0.30613, -0.59754, -0.85548, 0.6633
T1  DD  -0.87427, -0.00831, 0.78829, 0.60409, -0.90904, -0.13856, -0.80685, 0.48468
T2  DD  0.28997, -0.03668, -0.28362, 0.42831, 0.39332, -0.07474, -0.48694, -0.10497
T3  DD  -0.07783, 0.04415, -0.34355, -0.07161, 0.59105, -0.93145, 0.29402, 0.90334
T4  DD  0.36107, 0.05389, 0.27103, 0.47754, -0.00341, -0.79472, 0.82549, -0.29028
T5  DD  -0.01655, -0.20437, -0.36194, -0.90281, -0.26515, -0.4172, 0.36181, 0.51683
T6  DD  -0.12198, -0.45897, -0.35128, -0.85405, 0.84566, 0.99364, 0.13767, 0.78618
T7  DD  -0.03847, -0.81531, -0.18704, -0.33282, -0.95717, -0.6337, 0.10976, -0.88374
T8  DD  0.07904, -0.06245, 0.95181, -0.84223, -0.75583, -0.34406, 0.16785, 0.87519
T9  DD  -0.33485, 0.53875, -0.25173, 0.51317, -0.62441, -0.90698, -0.47925, 0.74832

F0  DD  -0.99103, 0.43842, 0.78128, -0.10985, -0.84714, -0.20558, -0.08925, -0.78608
F1  DD  0.15087, -0.56212, -0.87374, -0.3787, 0.86403, 0.60374, 0.01392, 0.84362
F2  DD  0.1114, 0.66496, -0.92633, 0.27408, 0.92439, 0.43692, 0.8298, -0.29647
F3  DD  0.87786, -0.8594, -0.42283, -0.97999, 0.58659, -0.327, -0.22656, 0.80896
F4  DD  0.43525, -0.8923, 0.86119, 0.78278, -0.01348, 0.98093, -0.56244, -0.75129
F5  DD  -0.73365, 0.28332, 0.63263, 0.17177, -0.38398, -0.43497, -0.31123, 0.73168
F6  DD  -0.57694, -0.87713, -0.93622, 0.89397, 0.93117, 0.40775, 0.2323, -0.30718
F7  DD  0.91059, 0.75966, 0.60118, 0.73186, 0.32178, 0.88296, -0.90087, -0.26367
F8  DD  0.3463, -0.89397, 0.99108, 0.13557, 0.50122, -0.8724, 0.43385, 0.00167
F9  DD  0.88121, 0.36469, -0.29829, 0.21429, 0.31395, 0.2734, 0.43267, -0.78192

TEQ DB 'In Triangle',0DH,0AH,'$'
FEQ DB 'Not In Triangle',0DH,0AH,'$'

Saída

In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
Not In Triangle
640KB
fonte
1

C 414 (era 465)

Golfe

#define D double 
int F(D ax,D ay,D bx,D by,D cx,D cy,D px,D py){int y=0;double J,K;D m=(ax-bx<0.001)?(by-ay)/(ax-bx):1000;D b=m*ax+ay;J=m*cx-cy+b;K=m*px-py+b;if(J*K>=0)y=1;return y;}D T[8],k;int i,n;void G(){while(i<8){scanf("%lf",&k);T[i++]=k;}n+=F(T[2],T[3],T[4],T[5],T[6],T[7],T[0],T[1]);n+=F(T[4],T[5],T[6],T[7],T[2],T[3],T[0],T[1]);n+=F(T[2],T[3],T[6],T[7],T[4],T[5],T[0],T[1]);printf(n==3?"True":"False");}

Declaração de função original adicionada para explicação

/**
* determine if points C & P are on same side of line AB
* return 1 if true, 0 otherwise
*/
int PointsSameSide(D ax,D ay,D bx,D by,D cx, D cy, D px, D py);

Reescrita como uma função nomeada: insira via stdin uma cada linha ou todas em uma linha separada por espaço.

#define D double
int F(D ax,D ay,D bx,D by,D cx, D cy, D px, D py)
{
int y=0;
double J,K;
D m = (ax-bx<0.001)?(by-ay)/(ax-bx):1000;
D b = m*ax+ay;
J=m*cx-cy+b;
K=m*px-py+b;
if(J*K>=0)y=1;
return y;
}
double T[8],k;
int i,n;
void G()
{
while(i<8){scanf("%lf",&k);T[i++]=k;}
n+=F(T[2],T[3],T[4],T[5],T[6],T[7],T[0],T[1]);
n+=F(T[4],T[5],T[6],T[7],T[2],T[3],T[0],T[1]);
n+=F(T[2],T[3],T[6],T[7],T[4],T[5],T[0],T[1]);
printf(n==3?"True":"False");
}
bacchusbeale
fonte
3
Você pode salvar alguns bytes se livrando de novas linhas e espaços desnecessários. Além disso, você doubleredefiniu como Dmas ainda o usa doubleno código.
gronostaj
1

Java, 149 caracteres

g=Math.atan2(100*(d-y),(a-x));h=Math.atan2(100*(e-y),(b-x));i=Math.atan2(100*(f-y),(c-x));k=Math.round(Math.abs(g-h)+Math.abs(h-i)+Math.abs(i-g))==6;

Horrível, considerando que tenho que escrever "Matemática". toda vez. Este é o programa atual:

package mathPackage;
public class InTriangle {
public static void main(String[] args) {
    boolean k;
    double a=-1,b=0,c=1,d=0,e=1,f=0,x=0,y=0.4;
    double g,h,i;
    g=Math.atan2(100*(d-y),(a-x));
    h=Math.atan2(100*(e-y),(b-x));
    i=Math.atan2(100*(f-y),(c-x));
    k=Math.round(Math.abs(g-h)+Math.abs(h-i)+Math.abs(i-g))==6;
    System.out.println(k);
    System.out.println(g);
    System.out.println(h);
    System.out.println(i);
    System.out.print(Math.abs(g-h)+Math.abs(h-i)+Math.abs(i-g));
}
}

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.

colorado777
fonte
11
Para que servem 100*?
Xnor
1

JavaScript 125/198

Se pontos são fornecidos em 8 argumentos:

function d(x,y,a,b,c,d,e,f){function z(a,b,c,d){return(y-b)*(c-a)-(x-a)*(d-b)>0}return(z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1}

Se pontos são fornecidos em uma matriz bidimensional:

function c(s){return (z(s[1][0],s[1][1],s[2][0],s[2][1])+z(s[2][0],s[2][1],s[3][0],s[3][1])+z(s[3][0],s[3][1],s[1][0],s[1][1]))%3<1;function z(a,b,c,d){return (s[0][1]-b)*(c-a)-(s[0][0]-a)*(d-b)>0}}

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:

(y-b)(c-a) - (x-a)(d-b)

que indica o ponto em que lado de uma linha é derivado de reorganizar a definição de inclinação:

            m = (y2-y1)/(x2-x1)
      (y2-y1) = m(x2-x1)
       (y-y1) = m(x-x1)     ,substituting point we are testing (x,y) to be the 2nd point
       (y-y1) = (x-x1)(y2-y1)/(x2-x1)  ,substitute back the original definition of m
(y-y1)(x2-x1) = (x-x1)(y2-y1)    <-- left side will be greater than the right side, if
                                     the point is on the left; otherwise, it's on the right
            0 = (y-b)(c-a)-(x-a)(d-b) ,where (a,b)=(x1,y1), (c,d)=(x2,y2)

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/

var l = [[-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],
         [-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]];

function d(x,y,a,b,c,d,e,f){function z(a,b,c,d){return(y-b)*(c-a)-(x-a)*(d-b)>0}return(z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1}

for(var i = 0; i < l.length; i++){
    console.log(d.apply(undefined,l[i]));    //10 true, 10 false
}

97 caracteres (sem contar espaços ou tabulações) contam se convertidos em CoffeeScript:

d=(x,y,a,b,c,d,e,f)->
    z=(a,b,c,d)->
        (y-b)*(c-a)-(x-a)*(d-b)>0
    (z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1

115 caracteres se convertidos em ES6:

d=(x,y,a,b,c,d,e,f)=>{z=(a,b,c,d)=>{return (y-b)*(c-a)-(x-a)*(d-b)>0};return(z(a,b,c,d)+z(c,d,e,f)+z(e,f,a,b))%3<1}
Derek 朕 會 功夫
fonte
Essa é a "matemática de vetores extravagante" que estou usando: D (embora não seja a abordagem de coordenadas barricêntricas de fantasia que algumas outras adotaram). Como a resposta mais votada, você pode salvar alguns bytes usando o ES6 e definindo as funções como d=(x,y,...)=>{...}. No seu caso, você pode economizar ainda mais usando o CoffeeScript, o que não é necessário return: pastebin.com/RVFk1D5k ... e, em qualquer caso, você pode salvar um byte usando em <1vez de ==0.
Martin Ender
@ m.buettner: o Pensei que a equação usada não tinha nada a ver com vetores (derivados de álgebra simples), mas aparentemente ambos produzem a mesma equação. A matemática é maravilhosa.
Derek朕會功夫
1

R, 23

Inspirado pelo MATLAB ,

SDMTools::pnt.in.poly()

chamado como SDMTools::pnt.in.poly(point,triangle)where pointé um vetor de comprimento 2 e triangleé uma matriz de vértices 3x2. SDMTools está disponível no CRAN.

shadowtalker
fonte
1

Mathematica, 38 caracteres

RegionMember[Polygon[#[[1]]],#[[2]]] &

Exemplo:

d = {{{0, 0}, {1, 0}, {.5, .7}}, {.5, .6}};

RegionMember[Polygon[#[[1]]], #[[2]]] & @ d

(* Verdade *)

David G. Stork
fonte
É padrão contar espaços como caracteres, mas presumivelmente aqui você pode removê-los sem que nada quebre.
xnor 8/02
11
Além disso, você precisa receber e produzir resultados, em vez de usar variáveis ​​predefinidas. Você pode pesquisar algumas respostas do Mathematica para ver como elas o fazem.
xnor 8/02
0

C (gcc) , 108 bytes

i;f(a,b,c,d,e,f,g,h)float a,b,c,d,e,f,g,h;{i=(e-=a)*(h-=b)>(f-=b)*(g-=a);i=(c-=a)*f>(d-=b)*e==i&i==g*d>h*c;}

Experimente online!

Leva três produtos cruzados e retorna 1se o sinal do componente não mudar.

teto
fonte