一。實現Bezier曲線的升階,降階和拖動。
#!/usr/bin/env python # -*- coding: utf-8 -*- 'My Bezier' import numpy as np from scipy.special import comb, perm from matplotlib import pyplot as plt class MyBezier: def __init__(self, line): self.line = line self.index_02 = None #保存拖動的這個點的索引 self.press = None # 狀態標識,1為按下,None為沒按下 self.pick = None # 狀態標識,1為選中點並按下,None為沒選中 self.motion = None #狀態標識,1為進入拖動,None為不拖動 self.xs = list() # 保存點的x坐標 self.ys = list() # 保存點的y坐標 self.cidpress = line.figure.canvas.mpl_connect('button_press_event', self.on_press) # 鼠標按下事件 self.cidrelease = line.figure.canvas.mpl_connect('button_release_event', self.on_release) # 鼠標放開事件 self.cidmotion = line.figure.canvas.mpl_connect('motion_notify_event', self.on_motion) # 鼠標拖動事件 self.cidpick = line.figure.canvas.mpl_connect('pick_event', self.on_picker) # 鼠標選中事件 def on_press(self, event): # 鼠標按下調用 if event.inaxes!=self.line.axes: return self.press = 1 def on_motion(self, event): # 鼠標拖動調用 if event.inaxes!=self.line.axes: return if self.press is None: return if self.pick is None: return if self.motion is None: # 整個if獲取鼠標選中的點是哪個點 self.motion = 1 x = self.xs xdata = event.xdata ydata = event.ydata index_01 = 0 for i in x: if abs(i - xdata) < 0.02: # 0.02 為點的半徑 if abs(self.ys[index_01] - ydata) < 0.02:break index_01 = index_01 + 1 self.index_02 = index_01 if self.index_02 is None: return self.xs[self.index_02] = event.xdata # 鼠標的坐標覆蓋選中的點的坐標 self.ys[self.index_02] = event.ydata self.draw_01() def on_release(self, event): # 鼠標按下調用 if event.inaxes!=self.line.axes: return if self.pick == None: # 如果不是選中點,那就添加點 self.xs.append(event.xdata) self.ys.append(event.ydata) if self.pick == 1 and self.motion != 1: # 如果是選中點,但不是拖動點,那就降階 x = self.xs xdata = event.xdata ydata = event.ydata index_01 = 0 for i in x: if abs(i - xdata) < 0.02: if abs(self.ys[index_01] - ydata) < 0.02:break index_01 = index_01 + 1 self.xs.pop(index_01) self.ys.pop(index_01) self.draw_01() self.pick = None # 所有狀態恢復,鼠標按下到稀放為一個周期 self.motion = None self.press = None self.index_02 = None def on_picker(self, event): # 選中調用 self.pick = 1 def draw_01(self): # 繪圖 self.line.clear() # 不清除的話會保留原有的圖 self.line.axis([0,1,0,1]) # x和y范圍0到1 self.bezier(self.xs,self.ys) # Bezier曲線 self.line.scatter(self.xs, self.ys,color='b',s=200, marker="o",picker=5) # 畫點 self.line.plot(self.xs, self.ys,color='r') # 畫線 self.line.figure.canvas.draw() # 重構子圖 def bezier(self,*args): # Bezier曲線公式轉換,獲取x和y t=np.linspace(0,1) # t 范圍0到1 le = len(args[0]) - 1 le_1 = 0 b_x,b_y = 0,0 for x in args[0]: b_x = b_x + x*(t**le_1)*((1-t)**le)*comb(len(args[0]) - 1,le_1) # comb 組合,perm 排列 le = le - 1 le_1 = le_1 + 1 le = len(args[0]) - 1 le_1 = 0 for y in args[1]: b_y = b_y + y*(t**le_1)*((1-t)**le)*comb(len(args[0]) - 1,le_1) le = le - 1 le_1 = le_1 + 1 self.line.plot(b_x,b_y) fig = plt.figure(2,figsize=(12,6)) #創建第2個繪圖對象,1200*600像素 ax = fig.add_subplot(111) #一行一列第一個子圖 ax.set_title('My Bezier') myBezier = MyBezier(ax) plt.xlabel('X') plt.ylabel('Y') plt.show()
二。運行結果

三。參考
http://blog.csdn.net/joogle/article/details/7975118
http://blog.csdn.net/wizardforcel/article/details/54782688
