Contar o número de lados em um polígono

18

Contar o número de lados em um polígono

O robô de contagem de polígonos decidiu viajar pelo mundo sem avisar ninguém antes, mas é crucial que o processo de contagem de polígonos não pare por muito tempo. Portanto, você tem a seguinte tarefa: Dada uma imagem em preto e branco de um polígono, seu programa / função deve retornar o número de lados.

O programa será enviado a um computador antigo de cartões perfurados e, como os cartões perfurados são muito caros hoje em dia, é melhor tentar tornar o programa o mais curto possível.

As arestas têm pelo menos 10 pixels de comprimento e os ângulos formados por duas arestas adjetivas são de pelo menos 10 °, mas não mais que 170 ° (ou novamente maiores que 190 °). O polígono está completamente contido na imagem, e o polígono e seu complemento estão conectados (não há ilhas isoladas), portanto essa entrada não seria válida:

insira a descrição da imagem aqui

Pontuação

Este é o codegolf, o que significa que o menor envio em bytes vence; o seu envio precisa encontrar o número correto de arestas para cada caso de teste. (E o envio também deve funcionar para outros casos, a otimização apenas para esses casos de teste não é permitida.)

Se você deseja enviar uma solução que não encontre o número correto a cada vez, também poderá enviá-lo, mas ele ficará atrás de todos os envios com melhor desempenho.

Inclua o número total no seu título de envio. (O erro total é a soma das diferenças absolutas entre o número real de lados e cada saída).

Casos de teste

n = 10

insira a descrição da imagem aquiinsira a descrição da imagem aqui

n = 36

insira a descrição da imagem aquiinsira a descrição da imagem aqui

n = 7

insira a descrição da imagem aquiinsira a descrição da imagem aqui

n = 5

insira a descrição da imagem aquiinsira a descrição da imagem aqui

Este não é um caso de teste, apenas por curiosidade: quantas arestas você obtém para esta entrada?

insira a descrição da imagem aqui

flawr
fonte
Vejo muitos ângulos nos seus casos de teste que são maiores que 170 °. Por exemplo, todos os ângulos "sem ponto" (os mais próximos do centro) na sua estrela.
Maçaneta
@ Doorknob É o ângulo menor que deve ser menor que 170 °.
lirtosiast
Sim, mas eles são novamente maiores que 190 °. O objetivo dessa restrição é eliminar exemplos em que os dois lados opostos sejam difíceis de distinguir.
flawr
2
Qual a cor do interior do polígono?
feersum
1
O programa vai ser transmitido para um computador de cartões perfurados antigos, e como punchcards são muito caros hoje em dia, é melhor você tentar fazer o seu programa mais curto possível :-)
Luis Mendo

Respostas:

12

Python 2 + PIL, sem erro, 313 307 bytes

from Image import*
I=open(sys.argv[1])
w,h=I.size;D=I.getdata()
B={i%w+i/w*1j for i in range(w*h)if D[i]!=D[0]}
n=d=1;o=v=q=p=max(B,key=abs)
while p-w:
 p+=d*1j;e=2*({p}<B)+({p+d}<B)
 if e!=2:e%=2;d*=1j-e*2j;p-=d/1j**e
 if abs(p-q)>5:
    t=(q-v)*(p-q).conjugate();q=p;w=o
    if.98*abs(t)>t.real:n+=1;v=p
print n

Pega um nome de arquivo de imagem na linha de comando e imprime o resultado em STDOUT.

Dá o resultado correto para todos os testes en = 28 para o círculo.

Explicação

O algoritmo funciona caminhando ao longo do perímetro do polígono e contando o número de vértices encontrados (detectados como alterações na direção). Começamos no pixel mais distante da origem, oque é garantidamente um vértice e, portanto, adjacente a uma aresta (ou seja, um limite entre um pixel em primeiro plano e um pixel em segundo plano). Nós controlamos nossa posição, po vértice mais recente ve o "ponto de verificação" mais recente q, todos inicialmente iguais a o. Também acompanhamos a direção da borda d, em relação ao pixel atual; dinicialmente aponta para leste, o que é uma direção segura, pois sabemos que há uma borda a leste deo, ou não seria o mais distante da origem. Nós nos movemos ao longo da borda, em uma direção perpendicular a d, de modo que daponte para a esquerda, ou seja, no sentido horário. Sempre que "caímos da aresta", ou seja, em qualquer situação pfora do polígono, ou onde o pixel à nossa esquerda (na direção de d) esteja dentro do polígono, ajustamos pe de dacordo antes de continuar.

Toda vez que a distância entre pe o último ponto de verificação qfica maior que 5, tentamos determinar se passamos por um vértice entre qe p: Comparamos o ângulo entre vq(ou seja, o vetor de vpara q), que é a direção geral do lado do polígono em que estávamos caminhando quando alcançamos o último ponto de verificação e qpo deslocamento entre o último ponto de verificação e a posição atual. Se o ângulo for maior que cerca de 10 °, concluímos que estamos andando por um lado diferente do polígono, aumentamos a contagem de vértices e ajustamos vo vértice atual para p. Em cada ponto de verificação, independentemente de detectarmos um vértice ou não, atualizamos qo último ponto de verificação parap. Continuamos dessa maneira até chegarmos oao ponto de partida e retornar o número de vértices encontrados (observe que a contagem de vértices é inicialmente 1, pois o ponto de partida oé um vértice).

As imagens abaixo mostram os vértices detectados. Observe que p, assumindo , a posição atual em cada ponto de verificação, como a posição do novo vértice, não é ideal, pois o vértice real provavelmente está em algum lugar entre o último ponto de verificação qe pao longo do perímetro. Como você pode ver, todos os vértices que não sejam o primeiro (geralmente, o vértice inferior direito) estão um pouco fora. Corrigir isso custaria mais bytes, mas parece estar funcionando bem o suficiente. Dito isto, é um pouco difícil não se ajustar demais com apenas quatro casos de teste.

n = 10 n = 36 n = 7 n = 5 Círculo

Ell
fonte
Obrigado por esta explicação detalhada! Eu amo suas ilustrações!
flawr
Se houver uma borda a leste de o, o outro extremo não estaria mais longe da origem?
Aditsu
1
@ aditsu Acho que a terminologia pode ser um pouco confusa aqui. Falamos sobre os lados do polígono, no sentido geométrico, e as bordas do (conjunto de pixels que compõem o) polígono, como um gráfico raster. oé o pixel de primeiro plano mais distante da origem; portanto, o pixel a leste deve ser um pixel de fundo; portanto, dizemos que há uma borda a leste de o.
Ell