Azules circulares

21

Escriba un programa o función que tome un número entero positivo N y recrea este patrón de círculos escalados para ajustarse a una imagen de píxeles N × N:

círculos elegantes

Esta imagen es un ejemplo de salida válido para N = 946.

En caso de que no esté claro, todos los círculos pequeños de color azul claro tienen el mismo radio y se colocan en los cuatro círculos de color azul oscuro de la misma manera. Los círculos azul oscuro tienen el doble de ese radio y están colocados de manera similar en el gran círculo azul claro.

  • Se pueden usar dos colores visualmente distintos en lugar de los dos tonos de azul.

  • El cuadrado de fondo necesita ser coloreado.

  • El suavizado es opcional.

  • Guarde la imagen en un archivo, muéstrela o canalice los datos de la imagen sin procesar a stdout.

  • Se permite cualquier formato de archivo de imagen común.

El código más corto en bytes gana.

Brownie señala si extiende los aspectos recursivos de este patrón de círculo a niveles adicionales. (Mantenga esto distinto de su entrada de desafío).

Pasatiempos de Calvin
fuente
¿Qué quiere decir con "el cuadrado de fondo necesita ser coloreado"? Si el fondo tiene un determinado color por defecto, ¿puedo usarlo como uno de los 2 colores sin rellenarlo explícitamente?
aditsu
Quiero decir, el BG no puede ser un tercer color diferente
Calvin's Hobbies

Respuestas:

5

CJam, 83 bytes

"P1"li___,.5f+2.@/f*1fm2m*{[3{_~mh1<[[VX][ZmqV]]_Wff*+@2f*f.+{~mh}$0=}*;0]0#2%}%]S*

Pruébalo en línea

CJam no tiene una funcionalidad de salida de imagen dedicada. Mi código genera una imagen en PBM ASCII. Para publicar, convertí esa imagen a PNG usando GIMP.

Tenga en cuenta que no se utilizó ninguna funcionalidad de dibujo circular, ni nada de eso. La imagen se calcula píxel por píxel.

Salida de muestra

Los grados más altos de la subdivisión se pueden crear fácilmente al aumentar la constante 3alrededor de la mitad del código.

Las imágenes de grado 4 y 5 se ven así:

Grado 4Grado 5

La secuencia general del código es:

  1. Genere las coordenadas de todos los píxeles, normalizadas al rango [-1.0, 1.0].
  2. Recorrer todos los píxeles.
  3. Pase sobre grados de subdivisión.
  4. Para cada subdivisión, verifique si el píxel está adentro / afuera, y guarde el resultado. La escala / traduce las coordenadas de píxel a los sistemas de coordenadas centrados en uno de los 4 sub-círculos. Elija el que las coordenadas transformadas están más cerca del centro.
  5. A partir de los resultados binarios dentro / fuera de cada grado, encuentre el primer 0, correspondiente al primer grado donde estaba el píxel afuera, y tome su módulo 2 para determinar el color del píxel.

Explicación:

"P1"    Start of header for PBM ASCII file.
li      Get input n.
__      Two copies for the width/height of the image in the PBM header.
_,      Generate [0 .. n - 1].
.5f+    Add 0.5 to each list entry, since we want to test the pixel centers.
2.@/    Calculate 2.0 / n, which is the distance between two pixels.
f*      Multiply the unscaled pixel coordinates with the pixel distance.
        We now have coordinates in the range [0.0, 2.0].
1fm     Subtract one from each, giving coordinates in range [-1.0, 1.0].
2m*     Cartesian power to calculate all y/x pairs.
{       Start loop over all pixel coordinates.
  [       Start wrapping the inside/outside results for all degrees.
  3{      Start loop over degrees.
    _~mh    Calculate distance from center.
    1<      Compare with 1. This gives inside/outside result for degree.
    [       Start building list of centers for 4 sub-circles.
    [VX]    One is at [0 1]. Note that coordinate order is y/x.
    [ZmqV]  Next one is at [sqrt(3) 0].
    ]       Wrap these two...
    _       ... and copy them.
    Wff*    Mirror all coordinates by multiplying with -1.
    +       Concatenate, giving the centers of all 4 sub-circles.
    @       Get current coordinates to top.
    2f*     Multiply them by 2. Note that the coordinates need to be scaled up by
            a factor 2 to give a circle with half the radius when we test the distance
            to the origin against 1.0.
    f.+     Add the current coordinates to the centers of all 4 sub-circles.
            For each sub-circle, this puts the current coordinates in a coordinate
            space with the origin at the center, and with a radius of 1.0
    {~mh}$  Sort them by distance to the origin...
    0=      ... and take the first one. This picks the sub-circle which has its
            center closest to the current coordinates.
            We now have one coordinate pair, for the closest sub-circle, and are
            ready for the next loop iteration, which tests the next degree of the
            subdivision.
  }*      End loop over degrees.
  ;       Have remaining coordinate pair on stack, pop it.
  0       Add a sentinel for find operation before, so that a 0 is always found.
  ]       End wrapping the inside/outside results for all degrees.
  0#      Find the first 0 (outside) degree.
  2%      Modulo 2 to determine color.
}%      End loop over all pixel coordinates.
]       Wrap the pieces of the PBM header and the pixel list.
S*      Join them with spaces, to produce the necessary spaces for the header.
Reto Koradi
fuente
17

Python 2 + PIL, 262 bytes

ingrese la descripción de la imagen aquí

Este enfoque determina el color de cada coordenada de píxel individual utilizando la función recursiva c. c(x,y,0)hace un círculo; c(x,y,1)hace un círculo con cuatro círculos cortados; c(x,y,2)renderiza la imagen en el OP. Cualquier cosa mayor que 2 me gana puntos de brownie.

import PIL.Image as I
d=3**.5/2
c=lambda x,y,l=0:c(x,y)&~any(c((x+i)*2,(y+j)*2,l-1)for i,j in[(.5,0),(-.5,0),(0,d),(0,-d)])if l else x*x+y*y<1
z=input()
f=lambda s:2.*s/z-1
I.frombytes("L",(z,z),"".join(" ~"[c(f(i%z),f(i/z),2)]for i in range(z*z))).save("p.png")

Versión sin golf:

from PIL import Image
import math
def in_shape(x,y, level=0):
    d = math.sqrt(3)/2
    if level == 0:
        return x**2 + y**2 <= 1
    else:
        t = True
        for dx,dy in [(0.5, 0), (-0.5, 0), (0, d), (0,-d)]:
            if in_shape((x+dx)*2, (y+dy)*2, level-1):
                t = False
        return in_shape(x,y) and t

f = lambda s: ((2*s / float(size))-1)

size = input()
img = Image.new("RGB", (size, size))
pix = img.load()
for i in range(size):
    for j in range(size):
        if in_shape(f(i), f(j), 2):
            pix[i,j] = (0,0,0)
        else:
            pix[i,j] = (255,255,255)
img.save("output.png")

Imagen extra recursiva extra:

ingrese la descripción de la imagen aquí

Kevin
fuente
En lugar de .save("p.png")solo usar.show()
Albert Renshaw
7

PostScript, 335 bytes.

%!
/D{def}def/B{bind D}D/E{exch}B/A{add}D/c{3 copy 3 -1 roll A E moveto 0 360 arc}B/f{5 dict begin/d E D/r E D/y E D/x E D gsave x y r c clip d 2 mod setgray x y r c fill d 0 gt{/h 3 sqrt 2 div r mul D/r r 2 div D/d d 1 sub D x r A y r d f x r sub y r d f x y h A r d f x y h sub r d f}if grestore end}B 512 2 div dup dup 2 f showpage

PostScript no es solo un formato de archivo de gráficos con capacidades vectoriales y de mapa de bits, en realidad es un lenguaje de programación completo de Turing basado en objetos. El código anterior es una implementación de función recursiva bastante sencilla. Todos los operadores PostScript son funciones, y es común redefinirlos para condensar código. Tenga en cuenta que PostScript utiliza la notación polaca inversa (también conocida como notación postfix).

Los intérpretes PostScript generalmente leen metadatos (como el tamaño de la página y el título) de comentarios especiales al comienzo del archivo; obviamente, he eliminado todos los comentarios esenciales de la firma PostScript %!, excepto el básico, de mi entrada, pero aún debería aparecer bien en cualquier intérprete PostScript estándar, por ejemplo, GhostScript u Okular. También se puede ver usando la utilidad de visualización que viene con ImageMagick / GraphicsMagick.

Tenga en cuenta que el archivo debe terminar en una nueva línea (que he incluido en mi recuento de bytes), o el intérprete puede molestarse.

El parámetro de tamaño Npara este código es 512; se divide por 2 y se duplica dos veces para crear los parámetros para la llamada inicial de la función recursiva f. La profundidad de recursión es 2, que se da justo antes de la fen 512 2 div dup dup 2 f. Para mantener el tamaño pequeño, la salida es en blanco y negro. Aunque puede establecer cualquier profundidad de recursión entera no negativa razonable, esta versión solo se ve bien con profundidades pares.

Esta imagen es un gráfico vectorial, por lo que se puede mostrar en cualquier resolución sin pixelización, dependiendo de la calidad y la configuración del intérprete / impresora PostScript utilizado. (FWIW, PostScript utiliza curvas cúbicas de Bézier para dibujar arcos circulares, con suficientes splines para garantizar que el error siempre sea inferior a un píxel en el espacio del dispositivo). Para verlo usando la pantalla de ImageMagick con una calidad razonablemente alta, puede hacer lo siguiente:

display -density 300 -geometry 512x512 -page 512x512

los mismos parámetros también son buenos si desea usar ImageMagick's convertpara convertirlo a otro formato. Por ejemplo, aquí hay una versión de 640x640 del código PostScript anterior convertido a PNG:

640x640 B & W círculo fractal


Aquí hay una versión un poco más grande que maneja el color RGB y las profundidades de recursión extrañas:

%!PS-Adobe-3.0
/D{def}def/N 512 D/d 2 D/B{bind D}D/E{exch}B/A{add}D/c{3 copy 3 -1 roll A E moveto 0 360 arc}B/k{2 mod 0 eq{.3 .6 .9}{0 .2 .5}ifelse setrgbcolor}B d 1 A k 0 0 N N rectfill/f{5 dict begin/d E D/r E D/y E D/x E D gsave x y r c clip d k x y r c fill d 0 gt{/h 3 sqrt 2 div r mul D/r r 2 div D/d d 1 sub D x r A y r d f x r sub y r d f x y h A r d f x y h sub r d f}if grestore end}B N 2 div dup dup d f showpage

También le permite establecer el parámetro de tamaño Ny la profundidad de recursión dcerca de la parte superior del script.

640x640 círculo de color fractal, profundidad == 2


Finalmente, aquí está la forma más legible del código. (Desafortunadamente, el resaltado de sintaxis utilizado aquí para PostScript deja mucho que desear, pero supongo que es mejor que nada ...). Los intérpretes inteligentes de PostScript leerán la geometría de la página del %%BoundingBox:comentario especial.

%!PS-Adobe-3.0
%%BoundingBox: 0 0 640 640
%%Title: Circle fractal
%%Creator: PM 2Ring
%%Creationdate: (Oct 29 2015)
%%Pages: 1 1
%%EndComments

% for http://codegolf.stackexchange.com/questions/61989/circular-blues

% ----------------------------------------------------------------------

16 dict begin

%Total image width & height in points / pixels
/N 640 def

%Maximum recursion depth
/Depth 4 def

% ----------------------------------------------------------------------

%Draw a circle centred at (x,y), radius r. x y r circle -
/circle{
    3 copy      % x y r  x y r
    3 -1 roll   % x y r  y r x
    add exch    % x y r  x+r y
    moveto
    0 360 arc 
}bind def

% ----------------------------------------------------------------------

%Select 1st color if n is even, select 2nd color if n is odd. n color -
/color{
    2 mod 0 eq
    {.36 .6 .9}
    {0 .25 .5}
    ifelse
    setrgbcolor
}bind def

%Do background square
Depth 1 add color
0 0 N N rectfill

/Q 3 sqrt 2 div def

%Recursive circle pattern. x y r Depth cfrac -
/cfrac{
    5 dict begin
    /Depth exch def
    /r exch def
    /y exch def
    /x exch def

    gsave
    x y r circle clip
    Depth color
    x y r circle fill

    Depth 0 gt
    {
        /dy Q r mul def
        /r r 2 div def
        /Depth Depth 1 sub def 

        x r add y r Depth cfrac
        x r sub y r Depth cfrac
        x y dy add r Depth cfrac
        x y dy sub r Depth cfrac
    }if
    grestore
    end
}bind def

%Call it!
N 2 div dup dup Depth cfrac

showpage

% ----------------------------------------------------------------------

%%Trailer
end
%%EOF

Y aquí está la salida de profundidad == 4 en formato PNG, una vez más creado usando convertir (y optimizado con optipng ):

640x640 círculo de color fractal, profundidad == 4

PM 2Ring
fuente
6

Python 2 + PIL, 361 bytes

import PIL.Image as p,PIL.ImageDraw as d
W=input()
q=W/4
h=2*q
t=3*q
e=W/8
o=int(q*3**.5)
I,J=[p.new("1",(s,s),s>h)for s in[W,h]]
Q=lambda i,x,y,s=q,c=0:d.Draw(i).ellipse((x,y,x+s,y+s),fill=c)
Q(I,0,0,W)
Q(J,0,0,h,1)
[Q(J,k,e)for k in[0,q]]
[Q(J,e,e+k/2)for k in[-o,o]]
[I.paste(1,k,J)for k in[(0,q,h,t),(h,q,4*q,t),(q,q-o,t,t-o),(q,q+o,t,t+o)]]
I.save("c.png")

Guarda la imagen en blanco y negro en el archivo c.png:

salida de ejemplo

Básicamente genero uno de los círculos de tamaño medio en la imagen J. Luego me uso como una máscara para pintar la forma en la imagen I, que tiene el círculo principal.

Podría acortarse usando I.show()al final en lugar de I.save("c.png"), pero no lo hice funcionar en Python 2. Si alguien puede confirmar que funciona en Python 2, cambiaré a eso.

El siguiente programa genera la imagen como en la pregunta (419 bytes):

import PIL.Image as p,PIL.ImageDraw as d
W=int(input())
q=W/4
h=2*q
t=3*q
e=W/8
o=int(q*3**.5)
I,J=[p.new(["1","RGB"][s>h],(s,s),s>h and"rgb(13,55,125)")for s in[W,h]]
Q=lambda i,x,y,s=q,c=0:d.Draw(i).ellipse((x,y,x+s,y+s),fill=c)
Q(I,0,0,W,"rgb(97,140,224)")
Q(J,0,0,h,1)
[Q(J,k,e)for k in[0,q]]
[Q(J,e,e+k/2)for k in[-o,o]]
[I.paste("rgb(13,55,125)",k,J)for k in[(0,q,h,t),(h,q,4*q,t),(q,q-o,t,t-o),(q,q+o,t,t+o)]]
I.save("c.png")
PurkkaKoodari
fuente
-1 no es tan bonito como la imagen de Calvin;)
Beta Decay
Puedo confirmar que .show () funciona
Albert Renshaw
Ok, gracias, lo usaré en lugar de save.
Kevin
3

SVG (1249 caracteres)

Sí, muchos personajes. Pero es estático y se presenta en cualquier tamaño, por lo que le da algo de bonificación.

<svg xmlns="http://www.w3.org/2000/svg"><path d="M15,33c-2.5,0-4.6,1.9-4.9,4.3c2.8,1.6,6.1,2.6,9.5,2.6c0.3-0.6,0.4-1.3,0.4-2C20,35.2,17.8,33,15,33zM15,7c2.8,0,5-2.2,5-5c0-0.7-0.1-1.4-0.4-2c-3.5,0.1-6.7,1-9.5,2.6C10.4,5.1,12.5,7,15,7zM25,33c-2.8,0-5,2.2-5,5c0,0.7,0.1,1.4,0.4,2c3.5-0.1,6.7-1,9.5-2.6C29.6,34.9,27.5,33,25,33zM25,7c2.5,0,4.6-1.9,4.9-4.3C27.1,1,23.9,0.1,20.4,0C20.1,0.6,20,1.3,20,2C20,4.7,22.2,7,25,7zM35,28.7C34.8,26,32.6,24,30,24s-4.8,2.1-5,4.7c-3-1.7-5-5-5-8.7c0,3.7-2,6.9-5,8.7C14.8,26,12.6,24,10,24S5.2,26,5,28.7c-3-1.7-5-5-5-8.7c0,7.4,4,13.9,10,17.3c0.1-1.2,0.4-2.4,0.8-3.4c0.9-1.9,2.3-3.5,4.1-4.5c0,0,0,0,0.1,0c0.2,2.6,2.3,4.7,5,4.7s4.8-2.1,5-4.7c0,0,0,0,0.1,0c1.8,1,3.2,2.6,4.1,4.5c0.5,1.1,0.8,2.2,0.8,3.4c6-3.5,10-9.9,10-17.3C40,23.7,38,26.9,35,28.7zM5,11.3c0.2,2.6,2.3,4.7,5,4.7s4.8-2.1,5-4.7c3,1.7,5,5,5,8.7c0-3.7,2-6.9,5-8.7c0.2,2.6,2.3,4.7,5,4.7s4.8-2.1,5-4.7c3,1.7,5,5,5,8.7c0-7.4-4-13.9-10-17.3c-0.1,1.2-0.4,2.4-0.8,3.4C28.3,8,26.8,9.6,25,10.6c0,0,0,0-0.1,0C24.8,8,22.6,6,20,6s-4.8,2.1-5,4.7c0,0,0,0-0.1,0c-1.8-1-3.2-2.6-4.1-4.5C10.4,5,10.1,3.9,10,2.6C4,6.1,0,12.6,0,20C0,16.3,2,13,5,11.3z"/><circle cx="15" cy="20" r="5"/><circle cx="5" cy="20" r="5"/><circle cx="35" cy="20" r="5"/><circle cx="25" cy="20" r="5"/></svg>

Fragmento visible:

svg { fill: #9FD7FF; background: #2176AA; }
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 40 40">
  <path d="M15,33c-2.5,0-4.6,1.9-4.9,4.3c2.8,1.6,6.1,2.6,9.5,2.6c0.3-0.6,0.4-1.3,0.4-2C20,35.2,17.8,33,15,33zM15,7c2.8,0,5-2.2,5-5c0-0.7-0.1-1.4-0.4-2c-3.5,0.1-6.7,1-9.5,2.6C10.4,5.1,12.5,7,15,7zM25,33c-2.8,0-5,2.2-5,5c0,0.7,0.1,1.4,0.4,2c3.5-0.1,6.7-1,9.5-2.6C29.6,34.9,27.5,33,25,33zM25,7c2.5,0,4.6-1.9,4.9-4.3C27.1,1,23.9,0.1,20.4,0C20.1,0.6,20,1.3,20,2C20,4.7,22.2,7,25,7zM35,28.7C34.8,26,32.6,24,30,24s-4.8,2.1-5,4.7c-3-1.7-5-5-5-8.7c0,3.7-2,6.9-5,8.7C14.8,26,12.6,24,10,24S5.2,26,5,28.7c-3-1.7-5-5-5-8.7c0,7.4,4,13.9,10,17.3c0.1-1.2,0.4-2.4,0.8-3.4c0.9-1.9,2.3-3.5,4.1-4.5c0,0,0,0,0.1,0c0.2,2.6,2.3,4.7,5,4.7s4.8-2.1,5-4.7c0,0,0,0,0.1,0c1.8,1,3.2,2.6,4.1,4.5c0.5,1.1,0.8,2.2,0.8,3.4c6-3.5,10-9.9,10-17.3C40,23.7,38,26.9,35,28.7zM5,11.3c0.2,2.6,2.3,4.7,5,4.7s4.8-2.1,5-4.7c3,1.7,5,5,5,8.7c0-3.7,2-6.9,5-8.7c0.2,2.6,2.3,4.7,5,4.7s4.8-2.1,5-4.7c3,1.7,5,5,5,8.7c0-7.4-4-13.9-10-17.3c-0.1,1.2-0.4,2.4-0.8,3.4C28.3,8,26.8,9.6,25,10.6c0,0,0,0-0.1,0C24.8,8,22.6,6,20,6s-4.8,2.1-5,4.7c0,0,0,0-0.1,0c-1.8-1-3.2-2.6-4.1-4.5C10.4,5,10.1,3.9,10,2.6C4,6.1,0,12.6,0,20C0,16.3,2,13,5,11.3z"/>
  <circle cx="15" cy="20" r="5"/>
  <circle cx="5" cy="20" r="5"/>
  <circle cx="35" cy="20" r="5"/>
  <circle cx="25" cy="20" r="5"/>
</svg>

meter
fuente
Tenga en cuenta que, como dijo Mego, SVG no cumple con nuestros criterios para calificar como lenguaje de programación . Sin embargo, el OP puede elegir permitir esta respuesta de todos modos; Depende de él.
Alex A.
SVG está bien en este caso.
Pasatiempos de Calvin
¿Se puede omitir el líder 0en constantes de coma flotante? Por ejemplo, reemplazar 0.4por .4? En la mayoría de los idiomas, eso es válido. Y un vistazo muy rápido de las especificaciones SVG sugiere que probablemente también debería funcionar.
Reto Koradi
@RetoKoradi Sí, y probablemente puedas descifrar algunos números más redondeando eficientemente, o cambiando el tamaño de una manera que necesites menos decimales, pero tbh. los caminos resultantes son demasiado complicados para que esto haga una gran diferencia. Pero puedo probar otra solución usando máscaras más tarde.
meter
2

Mathematica 336 359 bytes

Los principales objetos gráficos son regiones definidas a través de combinaciones lógicas de ecuaciones.

r=Red;i=ImplicitRegion;m=i[-2<x<2&&-2<y<2,{x,y}];n=Input[];
t[a_,b_,c_]:=i[(x+a)^2+(y+b)^2<=c,{x,y}];
a_~f~b_:={t[a,b,1],t[-.5+a,b,1/4],t[.5+a,b,1/4],t[a,b-.865,1/4],t[a,b+.865, 1/4]}
g@d_:=RegionIntersection[m,BooleanRegion[#1&&!#2&&!#3&&!#4&&!#5&,d]]
RegionPlot[{m,t[0,0,4],g@f[1,0],g@f[-1,0],g@f[0,1.75], 
g@f[0, -1.75]},ImageSize->n,PlotStyle->{r,Blue,r,r,r,r}]

Foto

DavidC
fuente
1

Java, 550

import javafx.application.*;import javafx.scene.*;import javafx.scene.layout.*;import javafx.scene.shape.*;import javafx.stage.*;public
class C extends Application{static long n;Shape d(float m,float k,float x,float y){float h=m/2;Shape
s=new Circle(x+h,y+h,h);return k>0?s.subtract(s,s.union(s.union(s.union(d(h,k-1,x,y+m/4),d(h,k-1,x+h,y+m/4)),d(h,k-1,x+m/4,y-m*.183f)),d(h,k-1,x+m/4,y+m*.683f))):s;}public
void start(Stage s){s.setScene(new Scene(new Pane(d(n,2,0,0))));s.show();}public
static void main(String[]a){n=Long.valueOf(a[0]);launch();}}

Mayormente solo experimentando con JavaFX.

Captura de pantalla:

captura de pantalla

Para los puntos de brownie, cambie el 2código ( d(n,2,0,0)) a un número diferente.

Versión anterior, 810

import javafx.application.*;import javafx.scene.*;import javafx.scene.canvas.*;import javafx.scene.effect.*;import javafx.scene.layout.*;import javafx.scene.paint.*;import javafx.stage.*;public
class C extends Application{static long n;Canvas c;GraphicsContext g;void
d(float m,float k,float x,float y){if(k>0){float
h=m/2;g.save();g.beginPath();g.arc(x+h,y+h,h,h,0,360);g.clip();g.fillRect(x,y,m,m);d(h,k-1,x,y+m/4);d(h,k-1,x+h,y+m/4);d(h,k-1,x+m/4,y-m*.183f);d(h,k-1,x+m/4,y+m*.683f);g.restore();}}public
void start(Stage s){c=new Canvas(n,n);g=c.getGraphicsContext2D();g.setGlobalBlendMode(BlendMode.DIFFERENCE);g.setFill(Color.TAN);g.fillRect(0,0,n,n);d(n,3,0,0);Pane
p=new Pane();p.getChildren().add(c);s.setScene(new Scene(p));s.show();}public
static void main(String[]a){n=Long.valueOf(a[0]);launch();}}

Deja algunos bordes no deseados como puede ver en esta captura de pantalla .

aditsu
fuente
0

JavaScript (ES6), 279

Cree recursivamente lienzos y agregue el lienzo secundario cuatro veces a su lienzo principal. En la capa inferior, el lienzo es un círculo único; ese lienzo se estampó cuatro veces en un lienzo de los padres, y después de que la lona se estampa cuatro veces en el lienzo final de máster.

(n,o=0)=>(r=o-2&&f(n/2,o+1),c=document.createElement`canvas`,X=c.getContext`2d`,d=(x,Q)=>(X.drawImage(r,x,k+Q*k*Math.sqrt(3)),d),c.width=c.height=n,m=n/2,k=n/4,X.fillStyle=o%2||"red",X.fill(X.clip(X.arc(m,m,m,0,7))),r&&d(0,0)(m,0)(k,-1)(k,1),o?c:location=c.toDataURL`image/jpeg`)

imagen de envío

Demo ejecutable:

Con espacios en blanco, comentarios y un poco descuidados:

f=(n,o=0)=>(
    // recursively create another canvas if we're not at the deepest layer
    var r;
    if(o < 2) { r = f(n/2,o+1); }

    // create this canvas
    c=document.createElement("canvas"),
    c.width=c.height=n,
    X=c.getContext("2d"),

    // helpful postions
    m=n/2, k=n/4, q=k*Math.sqrt(3),

    // draw a circle and clip future draws within this circle
    // either fills red (the shortest color name) or a non-color that defaults to black
    X.fillStyle= o%2 || "red",
    X.arc(m,m,m,0,7),
    X.clip(),
    X.fill(),

    // define a chainable `drawImage` alias (the `d` function returns itself)
    d=(x,y)=>(X.drawImage(r,x,y),d)

    // if we have a recursive canvas, draw it four times by chaining `d`
    if(r) { d(0,k)(m,k)(k,k-q)(k,k+q); }

    // if this is the top-layer (o==0), show the final jpeg
    if(o == 0) { location = c.toDataURL("image/jpeg"); }

    // return this canvas, to be used recursively
    c
)

Esto puede producir fácilmente capas más profundas de recursión cambiando el valor inicial o-2o cualquier o-zvalor mayor .

Tenga en cuenta que este envío solo se ejecutará en Firefox, debido al uso de las características de ES6 y la inconsistencia en la API del lienzo filly los clipargumentos.

apsillers
fuente