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

Creates a Sierpinski Gasket, by recursively partitioning an initial triangle (a,b,c) into three or four new triangles.

Python, 167 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 #!/usr/bin/env python # coding: UTF-8 # ## @package _16_sierpinski # # Draws a Sierpinski Gasket. # # Usage: _16_sierpinski [number_of_divisions] # # @author Paulo Roma Cavalcanti # @since 09/02/2016 # @see http://paulbourke.net/fractals/gasket/ # @see https://en.wikipedia.org/wiki/Sierpinski_triangle # @see http://ecademy.agnesscott.edu/~lriddle/ifs/siertri/siertri.htm # @see http://www.oftenpaper.net/sierpinski.htm import sys try: from tkinter import * # python 3 except ImportError: from Tkinter import * # python 2 ## Creates a Sierpinski Gasket, by recursively partitioning # an initial triangle (a,b,c) into three or four new triangles. # # - There will be: # - @f$3^{count}@f$ red triangles or # - @f$4^{count}@f$ if the fourth triangle is drawn. # # - The number of white triangles is a Geometric Progression, starting at 1 and with ratio 3, given by: # - P(0) = 0 # - P(n) = 3 * P(n-1) + 1 # - P(n) = @f$\frac{(3^n-1)}{2}.@f$ # # @param a first vertex coordinates. # @param b second vertex coordinates. # @param c third vertex coordinates. # @param n number of subdivisions on each edge (depth of recursion). # @param fourth whether to add the fourth triangle. # def Sierpinski(a, b, c, n, fourth=False): ## list of points (a set of triangles). points = [] ## Pushes three vertices to the list of points. def triangle( a, b, c ): points.append ( a ) points.append ( b ) points.append ( c ) ## Returns a point on segment p1-p2 corresponding to parameter s. def mix(p1,p2,s): return [(p1[0]+p2[0])*s, (p1[1]+p2[1])*s] ## Divides triangle (a,b,c), by recursively subdividing # each edge at its middle point, and connecting the new points. def divideTriangle( a, b, c, count ): # check for end of recursion if ( count == 0 ): triangle( a, b, c ) else: # bisect the sides ab = mix( a, b, 0.5 ) ac = mix( a, c, 0.5 ) bc = mix( b, c, 0.5 ) count -= 1 # three new triangles divideTriangle( a, ab, ac, count ) divideTriangle( c, ac, bc, count ) divideTriangle( b, bc, ab, count ) # add the middle triangle if ( fourth ): divideTriangle( ac, bc, ab, count ) divideTriangle (a, b, c, n) return points ## Draw triangles, given in points, on canvas c. def draw(c, points, contour=False): w = c.winfo_width()//2 h = c.winfo_height()//2 centerx = w centery = h c.delete(ALL) for i in range(0,len(points),3): if ( not contour ): c.create_polygon(centerx+w*points[i] [0],centery-h*points[i ][1], centerx+w*points[i+1][0],centery-h*points[i+1][1], centerx+w*points[i+2][0],centery-h*points[i+2][1], fill='red', outline='black') else: c.create_line(centerx+w*points[i] [0],centery-h*points[i ][1], centerx+w*points[i+1][0],centery-h*points[i+1][1], centerx+w*points[i+2][0],centery-h*points[i+2][1], centerx+w*points[i] [0],centery-h*points[i ][1], fill='black', width=2) ## Main program. def main(argv=None): ## Resize the graphics when the window changes. def resize(event=None): global pts draw(canvas, pts, cntVar.get()=='ON') ## Redraw the graphics when the scale changes def redraw(event=None): global pts # Initialize the corners of the gasket with three points. vertices = [ [ -1, -1 ], [ 0, 1 ], [ 1, -1 ] ] pg = lambda n: (3**n-1)//2 ndiv = slider.get() pts = Sierpinski( vertices[0], vertices[1], vertices[2], ndiv, fillVar.get()=='ON' ) lr.configure(text="Red Triangles = %d "%(len(pts)//3)) la.configure(text=" White Triangles = %d"%(pg(ndiv))) resize(event) ndiv = 2 if argv is None: argv = sys.argv if len(argv) > 1: try: ndiv = abs(int(argv[1])) except: ndiv = 3 root = Tk() root.title("Sierpinski Gasket") bot = Frame(root) bot.pack(side=BOTTOM) top = Frame(root) top.pack(side=TOP) canvas = Canvas(root,width=400,height=400); canvas.bind("", resize) canvas.pack(expand=YES,fill=BOTH) slider = Scale(bot, from_=0, to=8, command=redraw, orient=HORIZONTAL) slider.set(ndiv) slider.pack(side=LEFT, anchor = W) cntVar = StringVar() # create a checkbutton for the drawing style cntVar.set ( "OFF" ) c = Checkbutton (bot, text="Contour", variable=cntVar, onvalue="ON", offvalue="OFF", command=resize) c.pack(side=BOTTOM) fillVar = StringVar() # create another checkbutton for the number of triangles fillVar.set ( "OFF" ) c = Checkbutton (bot, text="Fill", variable=fillVar, onvalue="ON", offvalue="OFF", command=redraw) c.pack(side=LEFT) lr = Label(top, text="") lr.pack(side=LEFT,anchor = W) la = Label(top, text="") la.pack(side=RIGHT,anchor = E) redraw(None) mainloop() if __name__=='__main__': sys.exit(main()) 
 Created by Paulo Cavalcanti on Sat, 20 Feb 2016 (MIT)