ベジェ曲線パスを描く

2019/01/06

Python2.7.8

イラストレーターやGimpなどのグラフィックソフトでよくある3次ベジェ曲線によるパス。 パスはTkinterの機能にはないので、自作を試みてみた。

``` # -*- coding: utf-8 -*-

import Tkinter

class Node: p = [0.0,0.0] #self point p0 = [0.0,0.0] #control point p1 = [0.0,0.0] #control point p0_avoid = False p1_avoid = False

def __init__(self,p,p0,p1):
    self.p = p
    self.p0 = p0
    self.p1 = p1

class Path: x = 0.0 y = 0.0 nodes = [] closed = False steps = 20

def __init__(self,nodes = None):
    if nodes == None:
        return
    self.nodes = nodes

def points(self):
    if len(self.nodes) == 0:
        return []
    points = []
    points.append(self.nodes[0].p)
    for i in range(1,len(self.nodes)):
        points += self._segment_points(i-1,i)
    if self.closed:
        points += self._segment_points(i,0)
        points = points[:-1]
    return points

def _segment_points(self,i,j):
    points = []
    n0 = self.nodes[i]
    n1 = self.nodes[j]
    if n0.p1_avoid == True and n1.p0_avoid == True:
        points.append(n1.point())
    else:
        pts = self.bezier_curve_points(n0.p,n0.p1,n1.p0,n1.p)
        points += pts[1:]
    return points

def bezier_curve_points(self,p0,p1,p2,p3):
    points = []
    for i in range(self.steps+1):
        t = float(i)/self.steps
        x = (1-t)**3*p0[0]+3*(1-t)**2*t*p1[0]+3*(1-t)*t**2*p2[0]+t**3*p3[0]
        y = (1-t)**3*p0[1]+3*(1-t)**2*t*p1[1]+3*(1-t)*t**2*p2[1]+t**3*p3[1]
        points.append((x,y))
    return points

def main(): window = Tkinter.Tk() canvas = Tkinter.Canvas(window,width=300,height=200) canvas.pack()

n0 = Node([50,50],[50,10],[80,50])
n1 = Node([100,150],[100,110],[100,190])  
n2 = Node([250,100],[250,150],[180,30])

path = Path([n0,n1,n2])
path.closed = True
#n1.p1_avoid = True
#n2.p0_avoid = True

if path.closed:
    canvas.create_polygon(path.points(),fill='gray',outline='red')
else:
    canvas.create_line(path.points(),fill='red')
r = 3
for n in path.nodes:
    canvas.create_oval(n.p[0]-r,n.p[1]-r,n.p[0]+r,n.p[1]+r)
    canvas.create_oval(n.p0[0]-r,n.p0[1]-r,n.p0[0]+r,n.p0[1]+r)
    canvas.create_oval(n.p1[0]-r,n.p1[1]-r,n.p1[0]+r,n.p1[1]+r)
    canvas.create_line(n.p[0],n.p[1],n.p0[0],n.p0[1])
    canvas.create_line(n.p[0],n.p[1],n.p1[0],n.p1[1])

window.mainloop()

if name == 'main': main()