<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    迭代函數系統的分形?

    相關文檔: 迭代函數系統(IFS)

    _images/fractal_ifs01.png
    # -*- coding: utf-8 -*-
    import numpy as np
    import matplotlib.pyplot as pl
    import time
    
    # 蕨類植物葉子的迭代函數和其概率值
    eq1 = np.array([[0,0,0],[0,0.16,0]])
    p1 = 0.01
    
    eq2 = np.array([[0.2,-0.26,0],[0.23,0.22,1.6]])
    p2 = 0.07
    
    eq3 = np.array([[-0.15, 0.28, 0],[0.26,0.24,0.44]])
    p3 = 0.07
    
    eq4 = np.array([[0.85, 0.04, 0],[-0.04, 0.85, 1.6]])
    p4 = 0.85
    
    def ifs(p, eq, init, n):
        """
        進行函數迭代
        p: 每個函數的選擇概率列表
        eq: 迭代函數列表
        init: 迭代初始點
        n: 迭代次數
        
        返回值: 每次迭代所得的X坐標數組, Y坐標數組, 計算所用的函數下標    
        """
    
        # 迭代向量的初始化
        pos = np.ones(3, dtype=np.float)
        pos[:2] = init
        
        # 通過函數概率,計算函數的選擇序列
        p = np.add.accumulate(p)    
        rands = np.random.rand(n)
        select = np.ones(n, dtype=np.int)*(n-1)
        for i, x in enumerate(p[::-1]):
            select[rands<x] = len(p)-i-1
        
        # 結果的初始化
        result = np.zeros((n,2), dtype=np.float)
        c = np.zeros(n, dtype=np.float)
        
        for i in xrange(n):
            eqidx = select[i] # 所選的函數下標
            tmp = np.dot(eq[eqidx], pos) # 進行迭代
            pos[:2] = tmp # 更新迭代向量
    
            # 保存結果
            result[i] = tmp
            c[i] = eqidx
            
        return result[:,0], result[:, 1], c
    
    start = time.clock()
    x, y, c = ifs([p1,p2,p3,p4],[eq1,eq2,eq3,eq4], [0,0], 100000)
    print time.clock() - start
    pl.figure(figsize=(6,6))
    pl.subplot(121)
    pl.scatter(x, y, s=1, c="g", marker="s", linewidths=0)
    pl.axis("equal")
    pl.axis("off")
    pl.subplot(122)
    pl.scatter(x, y, s=1,c = c, marker="s", linewidths=0)
    pl.axis("equal")
    pl.axis("off")
    pl.subplots_adjust(left=0,right=1,bottom=0,top=1,wspace=0,hspace=0)
    pl.gcf().patch.set_facecolor("white")
    pl.show()
    

    迭代函數系統設計器?

    # -*- coding: utf-8 -*-
    from enthought.traits.ui.api import *
    from enthought.traits.ui.menu import OKCancelButtons
    from enthought.traits.api import *
    from enthought.traits.ui.wx.editor import Editor
    
    import matplotlib
    # matplotlib采用WXAgg為后臺,這樣才能將繪圖控件嵌入以wx為后臺界面庫的traitsUI窗口中
    matplotlib.use("WXAgg")
    from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
    from matplotlib.figure import Figure
    
    import numpy as np
    import thread
    import time
    import wx
    import pickle
    
    ITER_COUNT = 4000 # 一次ifs迭代的點數
    ITER_TIMES = 10   # 總共調用ifs的次數
    
    def triangle_area(triangle):
        """
        計算三角形的面積
        """
        A = triangle[0]
        B = triangle[1]
        C = triangle[2]
        AB = A-B
        AC = A-C
        return np.abs(np.cross(AB,AC))/2.0
    
    def solve_eq(triangle1, triangle2):
        """
        解方程,從triangle1變換到triangle2的變換系數
            triangle1,2是二維數組:
            x0,y0
            x1,y1
            x2,y2
        """
        x0,y0 = triangle1[0]
        x1,y1 = triangle1[1]
        x2,y2 = triangle1[2]
        
        a = np.zeros((6,6), dtype=np.float)
        b = triangle2.reshape(-1)
        a[0, 0:3] = x0,y0,1
        a[1, 3:6] = x0,y0,1
        a[2, 0:3] = x1,y1,1
        a[3, 3:6] = x1,y1,1
        a[4, 0:3] = x2,y2,1
        a[5, 3:6] = x2,y2,1
        
        c = np.linalg.solve(a, b)
        c.shape = (2,3)
        return c
        
    def ifs(p, eq, init, n):
        """
        進行函數迭代
        p: 每個函數的選擇概率列表
        eq: 迭代函數列表
        init: 迭代初始點
        n: 迭代次數
        
        返回值: 每次迭代所得的X坐標數組, Y坐標數組, 計算所用的函數下標    
        """
    
        # 迭代向量的初始化
        pos = np.ones(3, dtype=np.float)
        pos[:2] = init
        
        # 通過函數概率,計算函數的選擇序列
        p = np.add.accumulate(p)    
        rands = np.random.rand(n)
        select = np.ones(n, dtype=np.int)*(n-1)
        for i, x in enumerate(p[::-1]):
            select[rands<x] = len(p)-i-1
        
        # 結果的初始化
        result = np.zeros((n,2), dtype=np.float)
        c = np.zeros(n, dtype=np.float)
        
        for i in xrange(n):
            eqidx = select[i] # 所選的函數下標
            tmp = np.dot(eq[eqidx], pos) # 進行迭代
            pos[:2] = tmp # 更新迭代向量
    
            # 保存結果
            result[i] = tmp
            c[i] = eqidx
            
        return result[:,0], result[:, 1], c   
       
    class _MPLFigureEditor(Editor):
        """
        使用matplotlib figure的traits編輯器
        """
        scrollable = True
    
        def init(self, parent):
            self.control = self._create_canvas(parent)
    
        def update_editor(self):
            pass
    
        def _create_canvas(self, parent):
            panel = wx.Panel(parent, -1, style=wx.CLIP_CHILDREN)
            sizer = wx.BoxSizer(wx.VERTICAL)
            panel.SetSizer(sizer)
            mpl_control = FigureCanvas(panel, -1, self.value)
            sizer.Add(mpl_control, 1, wx.LEFT | wx.TOP | wx.GROW)          
            self.value.canvas.SetMinSize((10,10))
            return panel
    
    class MPLFigureEditor(BasicEditorFactory):
        """
        相當于traits.ui中的EditorFactory,它返回真正創建控件的類
        """    
        klass = _MPLFigureEditor
    
    class IFSTriangles(HasTraits):
        """
        三角形編輯器
        """
        version = Int(0) # 三角形更新標志
        
        def __init__(self, ax):
            super(IFSTriangles, self).__init__()
            self.colors = ["r","g","b","c","m","y","k"]        
            self.points = np.array([(0,0),(2,0),(2,4),(0,1),(1,1),(1,3),(1,1),(2,1),(2,3)], dtype=np.float)
            self.equations = self.get_eqs()
            self.ax = ax
            self.ax.set_ylim(-10,10)
            self.ax.set_xlim(-10,10)           
            canvas = ax.figure.canvas
            # 綁定canvas的鼠標事件
            canvas.mpl_connect('button_press_event', self.button_press_callback)
            canvas.mpl_connect('button_release_event', self.button_release_callback)        
            canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)    
            self.canvas = canvas
            self._ind = None
            self.background = None
            self.update_lines()
            
        def refresh(self):
            """
            重新繪制所有的三角形
            """
            self.update_lines()
            self.canvas.draw()
            self.version += 1        
            
        def del_triangle(self):
            """
            刪除最后一個三角形
            """
            self.points = self.points[:-3].copy()
            self.refresh()
            
        def add_triangle(self):
            """
            添加一個三角形
            """
            self.points = np.vstack((self.points, np.array([(0,0),(1,0),(0,1)],dtype=np.float)))
            self.refresh()
            
        def set_points(self, points):
            """
            直接設置三角形定點
            """
            self.points = points.copy()
            self.refresh()      
            
        def get_eqs(self):
            """
            計算所有的仿射方程
            """
            eqs = []
            for i in range(1,len(self.points)/3):
                eqs.append( solve_eq( self.points[:3,:], self.points[i*3:i*3+3,:]) )
            return eqs
                
        def get_areas(self):
            """
            通過三角形的面積計算仿射方程的迭代概率
            """
            areas = []
            for i in range(1, len(self.points)/3):
                areas.append( triangle_area(self.points[i*3:i*3+3,:]) )
            s = sum(areas)
            return [x/s for x in areas]
            
        def update_lines(self):
            """
            重新繪制所有的三角形
            """
            del self.ax.lines[:]
            for i in xrange(0,len(self.points),3):
                color = self.colors[i/3%len(self.colors)]
                x0, x1, x2 = self.points[i:i+3, 0]
                y0, y1, y2 = self.points[i:i+3, 1]
                type = color+"%so" 
                if i==0:
                    linewidth = 3
                else:
                    linewidth = 1
                self.ax.plot([x0,x1],[y0,y1], type % "-", linewidth=linewidth)
                self.ax.plot([x1,x2],[y1,y2], type % "--", linewidth=linewidth)
                self.ax.plot([x0,x2],[y0,y2], type % ":", linewidth=linewidth)
        
            self.ax.set_ylim(-10,10)
            self.ax.set_xlim(-10,10)        
        
        def button_release_callback(self, event):
            """
            鼠標按鍵松開事件
            """
            self._ind = None
    
        def button_press_callback(self, event):
            """
            鼠標按鍵按下事件
            """
            if event.inaxes!=self.ax: return
            if event.button != 1: return
            self._ind = self.get_ind_under_point(event.xdata, event.ydata)
            
        def get_ind_under_point(self, mx, my):
            """
            找到距離mx, my最近的頂點
            """
            for i, p in enumerate(self.points):
                if abs(mx-p[0]) < 0.5 and abs(my-p[1])< 0.5:
                    return i
            return None
            
        def motion_notify_callback(self, event):
            """
            鼠標移動事件
            """
            self.event = event
            if self._ind is None: return
            if event.inaxes != self.ax: return
            if event.button != 1: return
            x,y = event.xdata, event.ydata
            
            #更新定點坐標
            self.points[self._ind,:] = [x, y]
            
            i = self._ind / 3 * 3
            # 更新頂點對應的三角形線段
            x0, x1, x2 = self.points[i:i+3, 0]
            y0, y1, y2 = self.points[i:i+3, 1]        
            self.ax.lines[i].set_data([x0,x1],[y0,y1])
            self.ax.lines[i+1].set_data([x1,x2],[y1,y2])
            self.ax.lines[i+2].set_data([x0,x2],[y0,y2])
            
            # 背景為空時,捕捉背景
            if self.background == None:
                self.ax.clear()
                self.ax.set_axis_off()
                self.canvas.draw()
                self.background = self.canvas.copy_from_bbox(self.ax.bbox)
                self.update_lines()
                
            # 快速繪制所有三角形
            self.canvas.restore_region(self.background) #恢復背景
            # 繪制所有三角形
            for line in self.ax.lines:
                self.ax.draw_artist(line)
            self.canvas.blit(self.ax.bbox)
            
            self.version += 1
            
    class AskName(HasTraits):
        name = Str("")
        view = View(
            Item("name", label = u"名稱"),
            kind = "modal",
            buttons = OKCancelButtons 
        )
        
    class IFSHandler(Handler):
        """
        在界面顯示之前需要初始化的內容
        """
        def init(self, info):
            info.object.init_gui_component()
            return True
            
    class IFSDesigner(HasTraits):
        figure = Instance(Figure) # 控制繪圖控件的Figure對象
        ifs_triangle = Instance(IFSTriangles)
        add_button = Button(u"添加三角形")
        del_button = Button(u"刪除三角形")
        save_button = Button(u"保存當前IFS")
        unsave_button = Button(u"刪除當前IFS")
        clear = Bool(True)
        exit = Bool(False)
        ifs_names = List()
        ifs_points = List()
        current_name = Str
        
        view = View(
            VGroup(
                HGroup(
                    Item("add_button"),
                    Item("del_button"),
                    Item("current_name", editor = EnumEditor(name="object.ifs_names")),
                    Item("save_button"),                
                    Item("unsave_button"),
                    show_labels = False
                ),
                Item("figure", editor=MPLFigureEditor(), show_label=False, width=600),
            ),
            resizable = True,
            height = 350,
            width = 600,
            title = u"迭代函數系統設計器",
            handler = IFSHandler()
        )
        
        def _current_name_changed(self):
            self.ifs_triangle.set_points( self.ifs_points[ self.ifs_names.index(self.current_name) ] )
    
                
        def _add_button_fired(self):
            """
            添加三角形按鈕事件處理
            """
            self.ifs_triangle.add_triangle()
            
        def _del_button_fired(self):
            self.ifs_triangle.del_triangle()
            
        def _unsave_button_fired(self):
            if self.current_name in self.ifs_names:
                index = self.ifs_names.index(self.current_name)
                del self.ifs_names[index]
                del self.ifs_points[index]
                self.save_data()
            
        def _save_button_fired(self):
            """
            保存按鈕處理
            """
            ask = AskName(name = self.current_name)
            if ask.configure_traits():
                if ask.name not in self.ifs_names:
                    self.ifs_names.append( ask.name )
                    self.ifs_points.append( self.ifs_triangle.points.copy() )
                else:
                    index = self.ifs_names.index(ask.name)
                    self.ifs_names[index] = ask.name
                    self.ifs_points[index] = self.ifs_triangle.points.copy()    
                self.save_data()
        
        def save_data(self):               
            with file("IFS.data", "wb") as f:
                pickle.dump(self.ifs_names[:], f) # ifs_names不是list,因此需要先轉換為list
                for data in self.ifs_points:
                    np.save(f, data) # 保存多個數組
    
        def ifs_calculate(self):
            """
            在別的線程中計算
            """
            def draw_points(x, y, c):
                if len(self.ax2.collections) < ITER_TIMES:
                    try:
                        self.ax2.scatter(x, y, s=1, c=c, marker="s", linewidths=0)
                        self.ax2.set_axis_off()
                        self.ax2.axis("equal")
                        self.figure.canvas.draw()   
                    except:
                        pass
                    
            def clear_points():
                self.ax2.clear()
    
            while 1:
                try:
                    if self.exit == True:
                        break
                    if self.clear == True:
                        self.clear = False
                        self.initpos = [0, 0]
                        # 不繪制迭代的初始100個點
                        x, y, c = ifs( self.ifs_triangle.get_areas(), self.ifs_triangle.get_eqs(), self.initpos, 100)
                        self.initpos = [x[-1], y[-1]]
                        self.ax2.clear()
        
                    x, y, c = ifs( self.ifs_triangle.get_areas(), self.ifs_triangle.get_eqs(), self.initpos, ITER_COUNT)
                    if np.max(np.abs(x)) < 1000000 and np.max(np.abs(y)) < 1000000:
                        self.initpos = [x[-1], y[-1]]
                        wx.CallAfter( draw_points, x, y, c )
                    time.sleep(0.05)
                except:
                    pass
        
        @on_trait_change("ifs_triangle.version")
        def on_ifs_version_changed(self):
            """
            當三角形更新時,重新繪制所有的迭代點
            """
            self.clear = True
            
        def _figure_default(self):
            """
            figure屬性的缺省值,直接創建一個Figure對象
            """
            figure = Figure()
            self.ax = figure.add_subplot(121)
            self.ax2 = figure.add_subplot(122)
            self.ax2.set_axis_off()
            self.ax.set_axis_off()    
            figure.subplots_adjust(left=0,right=1,bottom=0,top=1,wspace=0,hspace=0)
            figure.patch.set_facecolor("w")
            return figure   
           
        def init_gui_component(self):
            self.ifs_triangle = IFSTriangles(self.ax)
            self.figure.canvas.draw()
            thread.start_new_thread( self.ifs_calculate, ())     
            try:
                with file("ifs.data","rb") as f:
                    self.ifs_names = pickle.load(f)
                    self.ifs_points = []
                    for i in xrange(len(self.ifs_names)):
                        self.ifs_points.append(np.load(f))            
    
                if len(self.ifs_names) > 0:
                    self.current_name = self.ifs_names[-1]
            except:
                pass        
    
    designer = IFSDesigner()
    designer.configure_traits()
    designer.exit = True
    

    首頁目錄

    上一篇文章

    繪制Mandelbrot集合

    下一篇文章

    繪制L-System的分形圖

    97av