Fractal usando espirógrafo em Python
Introdução
Brinquedo espirógrafo que é usado para produzir padrões complexos usando engrenagens de plástico e canetas coloridas. Um fractal é uma curva que se desenvolve usando um padrão recorrente que se repete infinitamente em uma escala baixa. Fractais são usados para modelar estruturas (como flocos de neve) ou para descrever fenômenos parcialmente caóticos.
O espirógrafo pode ser usado para desenhar vários fractais. Alguns deles são dados abaixo
Você pode visitar benice-equation-blogspot.in para mais projetos de fractais com sua equação paramétrica. Alguns deles são dados abaixo
Matemática atrás da cortina
Estas são as duas equações paramétricas para formar os fractais do espirógrafo; para entender essas equações, você deve considerar uma figura generalizada do espirógrafo.
Para a parte da matemática, você pode consultar o Wiki, embora eu tente explicar um pouco dessa matemática em um breve resumo aqui. Se estivermos interessados em matemática, você pode verificar os links mencionados. Portanto, a partir de agora, essas várias curvas podem ser desenhadas usando uma equação paramétrica e, variando alguns valores dessa equação, podemos obter diferentes fractais. Então aqui está a equação paramétrica:
Onde,
R é um parâmetro de escala e não afeta a estrutura do espirógrafo.
e,
Então, agora vamos tentar implementar isso no código.
import
random, argparse
import
math
import
turtle
from
PIL
import
Image
from
datetime
import
datetime
from
fractions
import
gcd
class
Spiro:
def
__init__(
self
, xc, yc, col, R, r, l):
self
.t
=
turtle.Turtle()
self
.t.shape(
'turtle'
)
self
.step
=
5
self
.drawingComplete
=
False
self
.setparams(xc, yc, col, R, r, l)
self
.restart()
def
setparams(
self
, xc, yc, col, R, r, l):
self
.xc
=
xc
self
.yc
=
yc
self
.R
=
int
(R)
self
.r
=
int
(r)
self
.l
=
l
self
.col
=
col
gcdVal
=
gcd(
self
.r,
self
.R)
self
.nRot
=
self
.r
/
/
gcdVal
self
.k
=
r
/
float
(R)
self
.t.color(
*
col)
self
.a
=
0
def
restart(
self
):
self
.drawingComplete
=
False
self
.t.showturtle()
self
.t.up()
R, k, l
=
self
.R,
self
.k,
self
.l
a
=
0.0
x
=
R
*
((
1
-
k)
*
math.cos(a)
+
l
*
k
*
math.cos((
1
-
k)
*
a
/
k))
y
=
R
*
((
1
-
k)
*
math.sin(a)
-
l
*
k
*
math.sin((
1
-
k)
*
a
/
k))
self
.t.setpos(
self
.xc
+
x,
self
.yc
+
y)
self
.t.down()
def
draw(
self
):
R, k, l
=
self
.R,
self
.k,
self
.l
for
i
in
range
(
0
,
360
*
self
.nRot
+
1
,
self
.step):
a
=
math.radians(i)
x
=
R
*
((
1
-
k)
*
math.cos(a)
+
l
*
k
*
math.cos((
1
-
k)
*
a
/
k))
y
=
R
*
((
1
-
k)
*
math.sin(a)
-
l
*
k
*
math.sin((
1
-
k)
*
a
/
k))
self
.t.setpos(
self
.xc
+
x,
self
.yc
+
y)
self
.t.hideturtle()
def
update(
self
):
if
self
.drawingComplete:
return
self
.a
+
=
self
.step
R, k, l
=
self
.R,
self
.k,
self
.l
a
=
math.radians(
self
.a)
x
=
self
.R
*
((
1
-
k)
*
math.cos(a)
+
l
*
k
*
math.cos((
1
-
k)
*
a
/
k))
y
=
self
.R
*
((
1
-
k)
*
math.sin(a)
-
l
*
k
*
math.sin((
1
-
k)
*
a
/
k))
self
.t.setpos(
self
.xc
+
x,
self
.yc
+
y)
if
self
.a >
=
360
*
self
.nRot:
self
.drawingComplete
=
True
self
.t.hideturtle()
def
clear(
self
):
self
.t.clear()
class
SpiroAnimator:
def
__init__(
self
, N):
self
.deltaT
=
10
self
.width
=
turtle.window_width()
self
.height
=
turtle.window_height()
self
.spiros
=
[]
for
i
in
range
(N):
rparams
=
self
.genRandomParams()
spiro
=
Spiro(
*
rparams)
self
.spiros.append(spiro)
turtle.ontimer(
self
.update,
self
.deltaT)
def
restart(
self
):
for
spiro
in
self
.spiros:
spiro.clear()
rparams
=
self
.genRandomParams()
spiro.setparams(
*
rparams)
spiro.restart()
def
genRandomParams(
self
):
width, height
=
self
.width,
self
.height
R
=
random.randint(
50
,
min
(width, height)
/
/
2
)
r
=
random.randint(
10
,
9
*
R
/
/
10
)
l
=
random.uniform(
0.1
,
0.9
)
xc
=
random.randint(
-
width
/
/
2
, width
/
/
2
)
yc
=
random.randint(
-
height
/
/
2
, height
/
/
2
)
col
=
(random.random(),
random.random(),
random.random())
return
(xc, yc, col, R, r, l)
def
update(
self
):
nComplete
=
0
for
spiro
in
self
.spiros:
spiro.update()
if
spiro.drawingComplete:
nComplete
+
=
1
if
nComplete
=
=
len
(
self
.spiros):
self
.restart()
turtle.ontimer(
self
.update,
self
.deltaT)
def
toggleTurtles(
self
):
for
spiro
in
self
.spiros:
if
spiro.t.isvisible():
spiro.t.hideturtle()
else
:
spiro.t.showturtle()
def
saveDrawing():
turtle.hideturtle()
dateStr
=
(datetime.now()).strftime(
"%d%b%Y-%H%M%S"
)
fileName
=
'spiro-'
+
dateStr
(
'saving drawing to %s.eps/png'
%
fileName)
canvas
=
turtle.getcanvas()
canvas.postscript(
file
=
fileName
+
'.eps'
)
img
=
Image.
open
(fileName
+
'.eps'
)
img.save(fileName
+
'.png'
,
'png'
)
turtle.showturtle()
def
main():
(
'generating spirograph...'
)
descStr
=
parser
=
argparse.ArgumentParser(description
=
descStr)
parser.add_argument(
'--sparams'
, nargs
=
3
, dest
=
'sparams'
, required
=
False
,
help
=
"The three arguments in sparams: R, r, l."
)
args
=
parser.parse_args()
turtle.setup(width
=
0.8
)
turtle.shape(
'turtle'
)
turtle.title(
"Spirographs!"
)
turtle.onkey(saveDrawing,
"s"
)
turtle.listen()
turtle.hideturtle()
if
args.sparams:
params
=
[
float
(x)
for
x
in
args.sparams]
col
=
(
0.0
,
0.0
,
0.0
)
spiro
=
Spiro(
0
,
0
, col,
*
params)
spiro.draw()
else
:
spiroAnim
=
SpiroAnimator(
4
)
turtle.onkey(spiroAnim.toggleTurtles,
"t"
)
turtle.onkey(spiroAnim.restart,
"space"
)
turtle.mainloop()
if
__name__
=
=
'__main__'
:
main()
Resultado:
O programa acima desenha 4 tipos diferentes de fractais espirográficos, tente gerar outros fractais e, em seguida, carregue seus links do github no comentário. Terei todo o gosto em ajudá-lo se ocorrer algum erro.
Este artigo é uma contribuição de Subhajit Saha . Se você gosta de GeeksforGeeks e gostaria de contribuir, você também pode escrever um artigo usando contribute.geeksforgeeks.org ou enviar o seu artigo para contribute@geeksforgeeks.org. Veja o seu artigo que aparece na página principal do GeeksforGeeks e ajude outros Geeks.
Escreva comentários se encontrar algo incorreto ou se quiser compartilhar mais informações sobre o tópico discutido acima.
As postagens do blog Acervo Lima te ajudaram? Nos ajude a manter o blog no ar!
Faça uma doação para manter o blog funcionando.
70% das doações são no valor de R$ 5,00...
Diógenes Lima da Silva