Ich habe mich ein wenig mit geometrisch konstruierbaren Fraktalen auseinandergesetzt (wie z.B. das Sierpinski-Dreieck in einem anderen Thread). In der "fractals.py" befinden sich die Klassen der einzelnen Fraktale. Die Instanzen habe ich dann jedoch in der Datei "test_fractals.py" erstellt. da mir das ganze so übersichtlicher erschien. Natürlich könnte man die Instanzen auch direkt in der "fractals.py" erstellen...
Voraussetzung ist hier die Python Imaging Library (PIL), die unter http://www.pythonware.com/products/pil/ erhältlich ist. Entwickelt wurde das ganze unter Python 2.4, getestet mit den Versionen 2.4 und 2.5.
Um die verschiedenen Fraktale zu generieren kann man die einzelnen Blöcke in der "test_fractals.py" ent-kommentieren (wie heisst das Gegenteil von "auskommentieren?

fractals.py
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# fractals.py
#
# Copyright 2006 Crush
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
'''
fractals.py -- foobar
'''
import Image
import ImageDraw
class Fractal:
'''
Die Klasse Fractal stellt die Grundmethoden fuer die verschiedenen
Subklassen bereit.
'''
def __init__(self, size, data):
self.data = data
self.image = Image.new('1', size, color = 255)
self.draw = ImageDraw.Draw(self.image)
#def new_image(self):
# '''
# Mit dieser Methode wird ein neues Bild mit den Spezifikationen aus
# self.data[1] erstellt.
# '''
# self.image = Image.new('', (self.data[1]), color = 255)
def save(self, filename):
'''
Speichern des Bildes.
'''
self.image.save(filename)
print 'saved as: %s' % filename
return True
def show(self):
'''docstring'''
self.image.show()
return True
class Sierpinski(Fractal):
'''
Klasse, die ein Sierpinski-Dreieck berechnen und zeichnen kann.
'''
def __init__(self, size, data):
Fractal.__init__(self, size, data)
def generate(self, n):
'''
Erstellen des Fraktals mit der Rekursionstiefe n.
'''
self.draw.line((self.data[0], self.data[1]), fill=0)
self.draw.line((self.data[1], self.data[2]), fill=0)
self.draw.line((self.data[0], self.data[2]), fill=0)
if n > 0:
self.stages(self.data, 0, n)
def stages(self, data, i, n):
'''docstring'''
x1 = (data[0][0] + data[1][0]) / 2.
y1 = (data[0][1] + data[1][1]) / 2.
x2 = (data[1][0] + data[2][0]) / 2.
y2 = (data[1][1] + data[2][1]) / 2.
x3 = (data[2][0] + data[0][0]) / 2.
y3 = (data[2][1] + data[0][1]) / 2.
data2 = ((x1, y1), (x2, y2), (x3, y3))
self.draw.line((data[1], data[2]), fill=0)
i += 1
if not i-1 == n:
self.stages((data[0], data2[0], data2[2]), i, n)
self.stages((data[1], data2[0], data2[1]), i, n)
self.stages((data[2], data2[1], data2[2]), i, n)
return True
class Peano(Fractal):
'''
Die Klasse Peano zeichnet eine Peano-Kurve.
'''
def __init__(self, size, data):
Fractal.__init__(self, size, data)
def generate(self, n):
'''docstring'''
#self.n = n
self.draw.line((self.data[0], self.data[1]), fill=0)
if n:
self.stages(self.data, 0, n)
def calc_points(self, data):
'''
So sind die Punkte beschriftet (ASCII-Art, Monospace-Font verwenden!):
p3----------p5
| |
| |
p1 p34| |p56 p2
---------------------------
| |
| |
| |
p4----------p6
'''
math = (
#p34
(lambda x, y: (2./3.)*x + (1./3.)*y),
#p3, p5
(
(lambda x, y, z: x - y + z),
(lambda x, y, z: x + y - z)
),
#p4, p6
(
(lambda x, y, z: x + y - z),
(lambda x, y, z: x - y + z)
),
#p56
(lambda x, y: (1./3.)*x + (2./3.)*y)
)
(p1x, p1y), (p2x, p2y) = data
p34x = math[0](p1x, p2x)
p34y = math[0](p1y, p2y)
p3x = math[1][0](p34x, p34y, p1y)
p3y = math[1][1](p34y, p34x, p1x)
p4x = math[2][0](p34x, p34y, p1y)
p4y = math[2][1](p34y, p34x, p1x)
p56x = math[3](p1x, p2x)
p56y = math[3](p1y, p2y)
p5x = math[2][0](p56x, p56y, p2y)
p5y = math[2][1](p56y, p56x, p2x)
p6x = math[1][0](p56x, p56y, p2y)
p6y = math[1][1](p56y, p56x, p2x)
p1, p2 = (p1x, p1y), (p2x, p2y)
p34, p56 = (p34x, p34y), (p56x, p56y)
p3, p4, p5, p6 = (p3x, p3y), (p4x, p4y), (p5x, p5y), (p6x, p6y)
return (p1, p2, p34, p56, p3, p4, p5, p6)
def stages(self, data, i, n):
'''docstring'''
p1, p2, p34, p56, p3, p4, p5, p6 = self.calc_points(data)
self.draw.line((p3, p4), fill=0)
self.draw.line((p3, p5), fill=0)
self.draw.line((p4, p6), fill=0)
self.draw.line((p5, p6), fill=0)
i += 1
if not i == n:
self.stages((p1, p34), i, n)
self.stages((p34, p3), i, n)
self.stages((p34, p4), i, n)
self.stages((p34, p56), i, n)
self.stages((p56, p5), i, n)
self.stages((p56, p6), i, n)
self.stages((p3, p5), i, n)
self.stages((p4, p6), i, n)
self.stages((p2, p56), i, n)
return True
class KochCurve(Fractal):
'''docstring'''
def __init__(self, size, data):
Fractal.__init__(self, size, data)
def generate(self, n):
'''docstring'''
self.draw.line((self.data[0], self.data[1]), fill=0)
if n > 0:
self.stages(self.data, 0, n)
def calc_points(self, data):
'''docstring'''
c = (3**(1./2.))*(1./2.)
math = (
#p3
(
lambda x, y: (1./2.)*x + (1./2.)*y
),
#p4
(
lambda x, y: (2./3.)*x + (1./3.)*y
),
#p6
(
lambda x, y: (1./3.)*x + (2./3.)*y
),
#p5
(
(lambda x, y, z: x + c*(y - z)),
(lambda x, y, z: x - c*(y - z))
)
)
(p1x, p1y), (p2x, p2y) = data
p3x = math[0](p1x, p2x)
p3y = math[0](p1y, p2y)
p4x = math[1](p1x, p2x)
p4y = math[1](p1y, p2y)
p6x = math[2](p1x, p2x)
p6y = math[2](p1y, p2y)
p5x = math[3][0](p3x, p6y, p4y)
p5y = math[3][1](p3y, p6x, p4x)
p1, p2 = (p1x, p1y), (p2x, p2y)
p4, p5, p6 = (p4x, p4y), (p5x, p5y), (p6x, p6y)
return (p1, p2, p4, p5, p6)
def stages(self, data, i, n):
'''docstring'''
p1, p2, p4, p5, p6 = self.calc_points(data)
self.draw.line((p1, p2), fill=255)
self.draw.line((p1, p4), fill=0)
self.draw.line((p6, p2), fill=0)
self.draw.line((p4, p5), fill=0)
self.draw.line((p5, p6), fill=0)
i += 1
if not i == n:
self.stages((p1, p4), i, n)
self.stages((p4, p5), i, n)
self.stages((p5, p6), i, n)
self.stages((p6, p2), i, n)
return True
class KochSnowflake(Fractal, KochCurve):
'''docstring'''
def __init__(self, size, data):
KochCurve.__init__(self, size, data)
def generate(self, n):
'''docstring'''
self.draw.line((self.data[0], self.data[1]), fill=0)
self.draw.line((self.data[0], self.data[2]), fill=0)
self.draw.line((self.data[1], self.data[2]), fill=0)
if n:
self.stages((self.data[1], self.data[0]), 0, n)
self.stages((self.data[2], self.data[1]), 0, n)
self.stages((self.data[0], self.data[2]), 0, n)
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import fractals
x = 1000
y = (3**(1./2.))/2 * x
size_sp = x, int(y+1)
data_sp = ((0, y),
(x, y),
((x/2), y-(x/2)*3**(0.5)))
size_pe = 900, 900
data_pe = ((100,300), (800, 700))
kx = 1200
ky = kx/2
data_k = ((0, ky/2), (kx, ky))
size_ks = (1000,)*2
x, y = ((3/4.)*size_ks[0],)*2
data_ks = ((100, y-100),
(x+100, y-100),
((x/2)+100, -100+y-(x/2)*3**(0.5)))
if __name__ == '__main__':
#sp = fractals.Sierpinski(size_sp, data_sp)
#sp.generate(3)
#sp.show()
#pe = fractals.Peano(size_pe, data_pe)
#pe.generate(3)
#pe.show()
#k = fractals.KochCurve((kx, ky), data_k)
#k.generate(3)
#k.show()
ks = fractals.KochSnowflake(size_ks, data_ks)
ks.generate(3)
ks.show()
print 'done'
Ach ja: Dokumentiert ist das ganze noch nicht wirklich toll, teilweise habe ich einfach ein "'''docstring'''" eingefügt, das mich daran erinnern sollte, das irgendwann mal noch richtig zu dokumentieren ...
Crush
Edit:
hier noch ein Bild um das beschriebene zu veranschaulichen:
