Welcome, guest | Sign In | My Account | Store | Cart

wxKoch draws a Koch snowflake fractal. It is based on C++ code written by Martin Bernreuther and included in the wxWindows tutorial.

Python, 169 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/usr/bin/env python

"""
wxKoch.py for wxPython/wxWindows 2
by Simon Foster, November 2001
based on wxKoch0.cpp
by Martin Bernreuther, Jan 2000
"""
from time import time
import math
import cPickle
import zlib

from wxPython.wx import *

[ ID_Quit, ID_About, ID_InpLevel ] = range(3)

ABOUT_TEXT = """\
Koch Snowflake for wxPython
by S. Foster, November 2001"""

PYTHON = """\
\x78\xDA\xAD\x94\x31\x6E\xC3\x30\x0C\x45\xF7\x9C\x82\x40\x07\x17\
\x20\xF0\xE1\xB4\x43\x33\x0A\x1D\x3C\xC6\x43\x16\xAE\x41\xD0\xA9\
\x41\xDD\xFB\x4F\xA5\x48\xC9\x96\x2C\xA5\x5D\x4A\x30\x76\xBE\xF5\
\x42\x52\xA4\x9C\xE7\xFB\xF7\xF1\x70\x19\x5E\x5F\x48\xFD\x8D\x8E\
\xC3\xE1\x7A\x19\x40\x37\x7A\xBF\x5F\x6F\x9F\xA6\x66\x55\x4F\xA3\
\xDA\x34\x99\x66\xD7\xD3\x34\x8E\xA6\x25\xEA\xD3\x78\x1A\x93\x0E\
\x51\xC7\xD5\xA4\x49\xF5\x79\xF9\xFA\x30\xB1\xF8\xE2\xFA\x63\x72\
\x03\xD4\x41\xAD\x15\x10\x44\xD4\x05\xBF\x41\x70\xEB\x51\x05\xB4\
\x2C\xEA\x0B\xFE\x80\x66\xF5\xF9\x5F\xA0\x9C\x0E\x0F\x21\x2B\xDA\
\x0A\x8F\x57\xF4\x20\x5B\xCC\xE6\x60\x03\x95\x88\x08\x9B\xC4\x0E\
\x2A\x19\x16\xE6\x3D\x95\xA0\xD4\x6D\x47\x1E\x41\x5B\x14\x20\x43\
\x1B\xE5\x10\xB3\x70\x4A\x04\xBD\xE9\xA7\x0B\xB9\xC5\x16\xE8\x55\
\xBF\xB5\x10\xC1\x23\xC1\xE3\x20\x26\x6E\xA1\xD8\xCA\x10\x52\x1C\
\x7A\x10\x89\x9C\xB1\xA2\xE2\xC1\xE2\xCE\xEE\xF4\x79\x08\xA9\x6E\
\x8A\x81\xA4\x0B\x29\x93\x91\x54\x50\xD3\x71\xB2\x7A\x6C\x5C\xB9\
\x1E\x69\x66\x17\x28\xAC\xC7\xBC\xC3\x20\xA7\xF3\xD3\x92\xC3\xD4\
\x0C\xEA\xB7\x45\x32\x93\x72\x7B\x91\x15\xB4\xC5\xF1\x60\x7E\xAE\
\xA4\x84\x6C\x36\x1B\xB3\xDE\x6A\x68\xCB\x56\x1B\xA8\x17\xA9\x58\
\x87\x8D\x60\x07\x71\x3A\x57\xEB\x1E\x6D\x03\xFB\xDD\x79\xE3\x39\
\xF7\xBF\xF9\xC3\xF0\xED\xF9\x6C\xEA\xB7\xAA\x84\xF6\x6B\x25\x84\
\x1F\x03\x50\x09\xE6"""

root3 = math.sqrt ( 3. )

def getIconData():
    return cPickle.loads( zlib.decompress( PYTHON ))

class wxKochFrame( wxFrame ):
    def __init__( self, title, pos, size ):
        wxFrame.__init__( self, None, -1,
                            title, pos = pos, size = size )
        
        icon = wxIconFromXPMData( getIconData() )
        self.SetIcon( icon )

        self.menuBar = wxMenuBar()

        self.menuFile = wxMenu()
        self.menuFile.Append( ID_InpLevel, "Input &Level...\tCtrl-D" )
        self.menuFile.AppendSeparator()
        self.menuFile.Append( ID_Quit, "E&xit...\tCtrl-X" )
        self.menuBar.Append( self.menuFile, "&File" ) ;

        self.menuHelp = wxMenu()
        self.menuHelp.Append( ID_About, "&About..." )
        self.menuBar.Append( self.menuHelp, "&Help" )

        self.SetMenuBar( self.menuBar )
        EVT_MENU( self, ID_Quit, self.OnQuit )
        EVT_MENU( self, ID_About, self.OnAbout )
        EVT_MENU( self, ID_InpLevel, self.OnInpLevel )

        EVT_SIZE( self, self.OnSize )
        EVT_PAINT( self, self.OnPaint )

        self.level = -1
        self.mdc = None

        self.CreateStatusBar()
        self.SetStatusText( 'Enter Level' )

    def OnQuit ( self, event ):
        self.Close( true )
        
    def OnAbout( self, event ):
        wxMessageBox ( __doc__, 
            "About wxKoch", wxOK|wxICON_INFORMATION, self )
            
    def OnInpLevel( self, event ):
        self.level = wxGetNumberFromUser( "", "Level: ", "Input Level",
                                        4, 0, 10, self )
        if self.level == -1:
            msg = "Invalid number entered or dialog cancelled."
            self.SetStatusText( msg )
        else:
            self.mdc = None
            self.Refresh()

    def OnSize( self, event ):
        self.mdc = None
        self.Refresh()
        
    def DrawEdge ( self, dc, n, x1, y1, x2, y2 ):
        if n > 0 :
            x3 = 2. * x1/3. + x2/3.
            y3 = 2. * y1/3. + y2/3.
            self.DrawEdge( dc, n-1, x1, y1, x3, y3 )
            x4 = x1/3. + 2. * x2/3.
            y4 = y1/3. + 2. * y2/3.
            x5 = .5 * ( x1+x2 ) - ( y2-y1 ) * root3 / 6.
            y5 = .5 * ( y1+y2 ) + ( x2-x1 ) * root3 / 6.
            self.DrawEdge( dc, n-1, x3, y3, x5, y5 )
            self.DrawEdge( dc, n-1, x5, y5, x4, y4 )
            self.DrawEdge( dc, n-1, x4, y4, x2, y2 )
        else:
            dc.DrawLine( x1, y1, x2, y2 )

    def OnPaint( self, event ):
        print '.',
        pdc = wxPaintDC( self )
        if self.level != -1:
            msg = ''
            start = time()
            width, height = self.GetClientSize()

            if not self.mdc:
                msg = 'Draw:'
                n = self.level
                d = height

                if width < height: d = width

                y1 = .5 * height + .25 * d
                y3 = .5 * height - .5 * d
                x1 = .5 * width - .25 * d * root3
                x2 = .5 * width + .25 * d * root3
                x3 = .5 * width

                self.mdc = wxMemoryDC()
                self.mdc.SelectObject( wxEmptyBitmap( width, height ))
                self.mdc.Clear()
                self.mdc.SetPen( wxPen( wxNamedColour( 'CADET BLUE' ), 1, wxSOLID ))
                self.mdc.BeginDrawing()

                self.DrawEdge( self.mdc, n, x1, y1, x2, y1 )
                self.DrawEdge( self.mdc, n, x2, y1, x3, y3 )
                self.DrawEdge( self.mdc, n, x3, y3, x1, y1 )

                self.mdc.EndDrawing()

            pdc.Blit( 0, 0, width, height, self.mdc, 0, 0 )
            msg += 'level %s in %s seconds' % ( self.level, time() - start )
            self.SetStatusText( msg )
        
class wxKochApp( wxApp ):

    def OnInit( self ):
        self.pframe = wxKochFrame(
                        "Koch Snowflake for wxPython", 
                        wxPoint( 50, 50 ),
                        wxSize( 200, 200 ))
        self.pframe.Show( true )
        self.SetTopWindow( self.pframe )
        return true

app = wxKochApp(0)
app.MainLoop()

Requires wxPython. Tested on Win32 using Python 2.2 but should be portable. Any feedback on other platforms would be appreciated.

1 comment

Kevin Altis 22 years, 2 months ago  # | flag

PythonCard contains a turtle graphics sample app. PythonCard http://pythoncard.sourceforge.net/ contains a turtle graphics sample app which include Koch curves and many other standard fractal patterns. You can program one or more turtles interactively or write standalone scripts. There are some sample shots of the turtles in action at http://pythoncard.sourceforge.net/samples3.html