Tecelagem de juntas - desenha um nó Sierpiński


33

Dado um número inteiro N> = 2, produza uma imagem mostrando um nó Sierpiński de grau N.

Por exemplo, aqui estão os nós dos graus 2, 3, 4 e 5:

Grau 2 Grau 3 Grau 4 Grau 5

Clique nas imagens para ver em tamanho maior (quanto maior o grau, maior a imagem).

Especificação

  1. Um nó Sierpiński de grau N é desenhado usando os vértices de um triângulo Sierpiński de grau N como pontos de orientação. Um triângulo de Sierpiński de grau N são três triângulos de Sierpiński de grau N-1 dispostos em um triângulo maior. Um triângulo de Sierpiński de grau 0 é um triângulo equilátero.
  2. Os menores triângulos componentes têm comprimento lateral 64, dando ao triângulo de Sierpiński no qual o nó se baseia um comprimento lateral total de 64 * 2 ^ N
  3. O centro do triângulo externo está posicionado no centro da imagem. Isso não fornece espaço em branco igual na parte superior e inferior.
  4. A saída é uma imagem quadrada do comprimento do lado teto (64 * 2 ^ N * 2 / ROOT3)onde teto (x)é ceiling(x), o menor número inteiro maior do que ou igual a x. Isso é grande o suficiente para que o vértice superior do triângulo de Sierpiński subjacente fique contido na imagem quando o centro do triângulo estiver no centro da imagem.
  5. A curva única deve passar por cima e por baixo de si mesma, estritamente alternando. As soluções podem escolher entre abaixo e depois ou mais ou menos.
  6. As imagens de exemplo mostram o primeiro plano preto e o fundo branco. Você pode escolher duas cores facilmente distinguíveis. Anti-aliasing é permitido, mas não necessário.
  7. Não deve haver espaços onde dois arcos se encontram ou onde a curva passa por cima ou por baixo de si mesma.
  8. A saída pode ser para qualquer arquivo de imagem no formato raster ou para qualquer arquivo de imagem no formato vetorial que inclua o tamanho de exibição padrão correto. Se você exibir diretamente na tela, ele deverá estar em um formato que permita a rolagem para ver a imagem inteira quando maior que a tela.

Determinação do centro, raio e espessura do arco

  1. O nó é construído como uma série de arcos circulares que se encontram em pontos onde suas tangentes são paralelas, para proporcionar uma junção perfeita. Esses arcos são exibidos como setores anulares (arcos com espessura).
  2. Os centros desses arcos são os vértices dos menores triângulos de cabeça para baixo. Cada um desses vértices é o centro de exatamente um arco.
  3. Cada arco tem um raio de 64 * ROOT3 / 2
  4. A exceção é que os arcos nos três triângulos mais externos (nos cantos do triângulo maior) têm um centro que é o ponto médio dos dois vértices internos adjacentes e, portanto, têm um raio de 64 * (ROOT3 / 2-1 / 2)
  5. Cada arco é representado com uma espessura total (diferença entre o raio interno e o raio externo) 64 * (ROOT3 / 2) / 4e as bordas pretas deste têm uma espessura de 64 * (ROOT3 / 2) / 16A curva deve ter essas bordas e não apenas uma faixa sólida.

Unidades de medida

  1. Todas as distâncias estão em pixels (1 é a distância horizontal ou vertical entre 2 pixels adjacentes).
  2. A raiz quadrada de 3 deve ter precisão de 7 algarismos significativos. Ou seja, seus cálculos devem ser equivalentes ao uso de um ROOT3 para que1.7320505 <= ROOT3 < 1.7320515

Pontuação

O código mais curto em bytes vence.


Para quem se pergunta, N = 0 e N = 1 não estão incluídos porque correspondem a um círculo e um trevo, que não correspondem exatamente ao padrão que se aplica a N> = 2. Eu esperava que a maioria das abordagens para esse desafio precisasse adicionar código de caso especial para 0 e 1, então decidi omiti-las.


1
Seria bom ter um diagrama para mostrar a que todos os números estão relacionados?
Trichoplax # 10/16

Antes de jogar minha resposta / adicionar cantos, são 7 números significativos realmente necessários para pequenos detalhes, como a espessura da linha, etc.? Uma precisão como "7 algarismos significativos ou 1 pixel, o que for maior" parece mais apropriada.
Level River St

@LevelRiverSt Como o tamanho da imagem é dimensionado com a entrada, até 7 números significativos são insuficientes para precisão de 1 pixel para N. maior padrão.
Trichoplax #

Sim, é necessário que a escala da imagem para números maiores de N. 7 em uma imagem de 1000000 x 1000000 corresponda a 0,1 pixels, mas com cálculos intermediários, pode ser pior que isso. Eu acho que algo stroke-width:3.464102parecido é um pouco excessivo se a ideia era obter precisão de 1 pixel. Vou seguir em frente e incluí-lo assim, se essa é a decisão.
Level River St

Respostas:


27

Ruby, 1168 932

Corrigido um erro da noite passada, mais golfe depois de esclarecer.

Este é (atualmente) um programa completo que aceita um número de stdin e gera um svgarquivo para stdout. Escolhi svg porque sabia que era possível atender a todos os requisitos da pergunta, mas havia alguns problemas. em particular, o SVG suporta apenas arcos de círculos como parte do pathobjeto e não os define em termos de seu centro, mas sim dos dois pontos de extremidade.

Código

n=gets.to_i
r=64*w=0.75**0.5
m=1<<n-2
z=128*m/w
a=(s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
")%[0,r-r*m*8/3]+"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"
p=2
m.times{|i|(i*2+1).times{|j|(p>>j)%8%3==2&&a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}
p^=p*4}
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

Saída N = 4

redimensionado pela troca de pilhas. Parece muito melhor como original.

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

No começo, considerei algo como http://euler.nmt.edu/~jstarret/sierpinski.html, em que o triângulo é dividido em três fios de cores diferentes, cada um dos quais forma um caminho de um canto para outro. Os círculos incompletos são mostrados como hexágonos incompletos lá. inscrever círculos dentro dos hexágonos mostra que o raio do círculo deve ser sqrt(3)/2o dobro do comprimento da linha lateral. Os fios podem ser construídos de forma recursiva, como mostrado, mas há uma complicação adicional, porque os cantos precisam ser arredondados e é difícil saber em qual direção fazer a curva, por isso não usei essa abordagem.

O que eu fiz foi o seguinte.

Na imagem abaixo, você pode ver que existem torções horizontais pertencentes às unidades N = 2 (em verde) dispostas em um triângulo sierpinski e torções de ponte adicionais (em azul).

É do conhecimento geral que os números ímpares no triângulo de Pascal formam um triângulo de sierpinski. Um triângulo sierpinski de dígitos binários pode ser obtido de maneira análoga, iniciando com o número p=1e copiando-o iterativamente p<<1.

Eu modifiquei essa abordagem, iniciando p=2e xerando iterativamente com p*4. Isso fornece um triângulo sierpinski alternando com colunas de zeros.

Agora podemos deslocar os direitos p e inspecionar os últimos três bits usando %8. Se estiverem 010, precisamos desenhar uma torção verde pertencente a uma unidade N = 2. se forem 101, precisamos desenhar uma torção azul e em ponte. Para testar esses dois números juntos, encontramos o módulo %3e, se este for 2, precisamos desenhar a torção.

Finalmente, além das torções horizontais, fazemos duas cópias giradas em 120 e 240 graus para desenhar as torções diagonais e completar a imagem. Tudo o que resta é adicionar os cantos.

Código comentado

n=gets.to_i

#r=vertical distance between rows 
r=64*w=0.75**0.5

#m=number of rows of horizontal twists
m=1<<n-2

#z=half the size of the viewport
z=128*m/w

#s=SVG common to all paths
s="<path style='fill:none;stroke:black;stroke-width:3.464102' transform='translate(%f %f)'
"

#initialize a with SVG to draw top corner loop. Set k and l to the SVG common to all arcs of 58*w and 70*w radius 
a=s%[0,r-r*m*8/3]+
"d='M18.11943,-2A#{b=r-6*w-32} #{b} 0 0,0 #{-b} 0#{k='A%f %f 0 0 '%([58*w]*2)}0 0,38.71692
M28.58980,1.968882#{l='A%f %f 0 0 '%([70*w]*2)}0 #{c=r+6*w-32} 0A#{c} #{c} 0 0,0 #{-c} 0#{l}0 -9 44.65423'/>"

#p is the pattern variable, top row of twists has one twist so set to binary 00000010
p=2

#loop vertically and horizontally
m.times{|i|
 (i*2+1).times{|j|

   #leftshift p. if 3 digits inspected are 010 or 101 
   (p>>j)%8%3==2&&

   #append to a, the common parts of a path...
   a<<s%[128*(j-i),r*3+r*i*4-r*m*8/3]+

   #...and the SVG for the front strand and left and right parts of the back strand (each strand has 2 borders)
"d='M-55,44.65423#{k}0 11.5,25.11473#{l}1 35.41020,1.968882
M-64,51.48786#{l}0 20.5,30.31089#{k}1 36.82830,13.17993
M-82.17170,-2.408529#{l}1 -11.5,25.11473#{k}0 0,38.71692
M-81.52984 8.35435#{k}1 -20.5,30.31089#{l}0 -9,44.65423
M9,44.65423#{k}0 81.52984,8.35435
M0,51.48786#{l}0 91.17169,13.17993'/>"}

#modify the pattern by xoring with 4 times itself for the next row
p^=p*4}

#output complete SVG of correct size with three copies of the finished pattern rotated through 0,120,240 degrees.
puts "<svg xmlns='http://www.w3.org/2000/svg' viewBox='#{-z} #{-z} #{e=2*z+1} #{e}' width='#{e}px' height='#{e}px'>"+
"<g transform='rotate(%d)'>#{a}</g>"*3%[0,120,240]+"</svg>"

insira a descrição da imagem aqui


Onde você diz "Parece muito melhor que o original", pode valer a pena adicionar algo como "(clique na imagem para ver em tamanho maior)" para quem não percebe.
Trichoplax #

@trichoplax não me ocorreu clicar na imagem. Mas, de qualquer forma, este é um PNG, porque a troca de pilhas não aceita imagens svg, portanto as bordas são deliberadamente borradas. Meu arquivo SVG local tem bordas muito mais nítidas e parece muito melhor.
Level River St

@trichoplax correção rápida do tamanho da imagem concluída. Golf mais outro dia.
Level River St

1
+1 excelente trabalho. Eu particularmente gosto da explicação detalhada com o diagrama codificado por cores.
Trichoplax

1
O hiperlink está morto.
mbomb007
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.