サンプルコード


コード1 (演習1):

from __future__ import print_function, division
import math
import copy
import turtle

# control polygon
cp = [(0,0), (100,200), (300,250), (400,0)]
# cp = [(0,0), (100,-200), (300,250), (400,0)]
# cp = [(0,0), (300,250), (400,-100), (200,0)]
# cp = [(0,0), (400,300), (-200,350), (200,0)]

# draw line segments
def draw_segments(ttl, points, color):
    ttl.penup()
    ttl.goto(points[0])
    ttl.color(color)
    ttl.pendown()
    for (x, y) in points:
        ttl.goto(x, y)

# calculate sequence of points on Bezier curve
def bezier3(cp, ndot):
    # cp: control polygon
    # ndot: number of dots
    bp = []  # dots on Bezier curve
    degree = 3
    # calculate the coordinates of dots
    for i in range(ndot + 1):
        t = i / ndot
        x =      # x座標の計算
        y =      # y座標の計算
        bp.append((x, y))
    return(bp)

# setup turtle
gamera = turtle.Turtle()
gamera.reset()
gamera.speed(0)

# draw control polygon
draw_segments(gamera, cp, "black")

# calculate dots on Bezier curve
bp = bezier3(cp, 20)

# draw Bezier curve
draw_segments(gamera, bp, "red")

# wait for the user to close the window
turtle.mainloop()



コード2 (演習2):

from __future__ import print_function, division
import math
import copy
import turtle

# control polygon
cp = [(0,0), (100,200), (300,250), (400,0)]
# cp = [(0,0), (100,-200), (300,250), (400,0)]
# cp = [(0,0), (300,250), (400,-100), (200,0)]
# cp = [(0,0), (400,300), (-200,350), (200,0)]
# cp = [(0,0), (100,200), (300,250)]
# cp = [(0,0), (100,200), (300,250), (400,0), (300, -50)]
# cp = [(0,0), (100,200), (300,250), (400,0), (300, -50), (150, 50)]

# draw line segments
def draw_segments(ttl, points, color):
    ttl.penup()
    ttl.goto(points[0])
    ttl.color(color)
    ttl.pendown()
    for (x, y) in points:
        ttl.goto(x, y)

# calculate sequence of points on Bezier curve
def bezier(cp, ndot):
    # cp: control polygon
    # ndot: number of dots
    cof = []  # binomial coefficients
    bp = []  # dots on Bezier curve
    degree = len(cp) - 1
    if degree < 1:
        return(cp)
    # calculate binomial coefficients
    for i in range(degree + 1):
        cof.append(math.factorial(degree)/(math.factorial(i) * math.factorial(degree - i)))
    #
    # この部分のコードを作成
    #
    return(bp)

# setup turtle
gamera = turtle.Turtle()
gamera.reset()
gamera.speed(0)

# draw control polygon
draw_segments(gamera, cp, "black")

# calculate dots on Bezier curve
bp = bezier(cp, 20)

# draw Bezier curve
draw_segments(gamera, bp, "red")

# wait for the user to close the window
turtle.mainloop()



コード3 (演習3):

# calculate the point at t on Bezier curve
def bezier_subdiv3(cp, t):
    # cp: control polygon
    # t: parameter
    pnt = copy.copy(cp)  # internally dividing points
    degree = 3
    # set index to access pnt[]
    index = 0
    # calculate internally dividing points
    #
    # この部分のコードを作成
    #
    return(pnt[index])

# calculate sequence of points on Bezier curve
def bezier3(cp, ndot):
    # cp: control polygon
    # ndot: number of dots
    bp = []  # dots on Bezier curve
    degree = 3
    # calculate the coordinates of dots
    for i in range(ndot + 1):
        t = i / ndot
        bp.append(bezier_subdiv3(cp, t))
    return(bp)

# calculate dots on Bezier curve
bp = bezier3(cp, 20)



コード4 (演習4):

# draw bezier curve using subdivision
def draw_bezier_subdiv3(ttl, cp, color):
    # cp: control polygon
    t = 0.5  # t: parameter
    bcf = []  # forward Bezier curve
    bcb = []  # backward Bezier curve
    pnt = copy.copy(cp)  # internally dividing points
    degree = 3
    # set control polygon of forward Bezier curve
    #
    # 前半のベジエ曲線の構築(制御点を bcf に格納)
    #
    # set control polygon of backward Bezier curve
    #
    # 後半のベジエ曲線の構築(制御点を bcb に格納)
    #
    # forward Bezier curve
    if flatness(bcf) == True:
        draw_segments(ttl, bcf, color)
    else:
        draw_bezier_subdiv(ttl, bcf, color)
    # backward Bezier curve
    if flatness(bcb) == True:
        draw_segments(ttl, bcb, color)
    else:
        draw_bezier_subdiv(ttl, bcb, color)
    #
    return()

# check the flatness
def flatness(cp):
    degree = len(cp) - 1
    if degree < 2:
        return(True)
    # baseline connecting endpoints
    a = cp[degree][1] - cp[0][1]
    b = -(cp[degree][0] - cp[0][0])
    c = -(a * cp[0][0] + b * cp[0][1])
    d = math.sqrt(a*a + b*b)
    # in case of short length (it's not exactly)
    if d < 2:
        return(True)
    # calculate the maximum distance
    max_dist = 0
    for i in range(degree - 1):
        # calculate the distance between baseline and point
        dist = abs(a * cp[i + 1][0] + b * cp[i + 1][1] + c) / d
        if dist > max_dist:
            max_dist = dist
    # check the flatness
    if max_dist < 2:
        return(True)
    else:
        return(False)

# draw Bezier curve
draw_bezier_subdiv3(gamera, cp, "red")



コード5 (演習5):





コード6 (演習6):

# draw bezier curve using subdivision
def draw_bezier_subdiv(ttl, cp, color):
    # cp: control polygon
    t = 0.5  # t: parameter
    bcf = []  # forward Bezier curve
    bcb = []  # backward Bezier curve
    pnt = copy.copy(cp)  # internally dividing points
    degree = len(cp) - 1
    if degree < 1:
        return(cp)
    # calculate internally dividing points
    stage = 0
    internal_division(pnt, t, degree, stage)
    # set control polygon of forward Bezier curve
    index = 0
    bcf.append(pnt[index])
    for i in range(degree):
        # pnt[]に格納された内分点のindexの計算
        bcf.append(pnt[index])
    # set control polygon of backward Bezier curve
    bcb.append(pnt[index])
    for i in range(degree):
        # pnt[]に格納された内分点のindexの計算
        bcb.append(pnt[index])
    # forward Bezier curve
    if flatness(bcf) == True:
        draw_segments(ttl, bcf, color)
    else:
        draw_bezier_subdiv(ttl, bcf, color)
    # backward Bezier curve
    if flatness(bcb) == True:
        draw_segments(ttl, bcb, color)
    else:
        draw_bezier_subdiv(ttl, bcb, color)
    #
    return()

# calculate internally dividing points
def internal_division(pnt, t, degree, stage):
    if stage == degree:
        return()
    # set offset to access pnt[]
    offset = 0
    for i in range(stage):
        offset += degree + 1 - i
    # calculate internally dividing point
    for i in range(degree - stage):
        x =     # 内分点のx座標
        y =     # 内分点のy座標
        pnt.append((x, y))
    # repeat the internal division process
    internal_division(pnt, t, degree, stage+1)
    return()

# draw Bezier curve
draw_bezier_subdiv(gamera, cp, "red")



コード7 (演習7):

from __future__ import print_function, division
import math
import turtle
import copy

# font and control polygon (x, y)
cpv1 = [(0,270), (50,200), (50,130)]
cpv2 = [(50,130), (50,80), (0,0)]
cpv3 = [(0,0), (30,50), (70,50), (120,100)]
cpv4 = [(120,100), (200,170), (190,270)]
fontv = [cpv1, cpv2, cpv3, cpv4]
cpi1 = [(0,0), (95,0), (180,270)]
cpi2 = [(180,270), (95,0), (225,0)]
cpi3 = [(224,326), (190,326), (190,360)]
cpi4 = [(190,360), (190,394), (224,394)]
cpi5 = [(224,394), (258,394), (258,360)]
cpi6 = [(258,360), (258,326), (224,326)]
fonti = [cpi1, cpi2, cpi3, cpi4, cpi5, cpi6]
cps1 = [(0,0), (78,0), (169,101), (225,270)]
cps2 = [(225,270), (304,169), (293,90)]
cps3 = [(293,90), (281,0), (225,-23), (113,68)]
cps4 = [(113,68), (197,0), (281,0)]
fonts = [cps1, cps2, cps3, cps4]
cpu1 = [(0,0), (56,0), (135,270)]
cpu2 = [(135,270), (56,0), (113,0)]
cpu3 = [(113,0), (203,0), (270,281)]
cpu4 = [(270,281), (203,0), (270,0)]
fontu = [cpu1, cpu2, cpu3, cpu4]
cpa1 = [(158,225), (146,281), (68,281), (15,158)]
cpa2 = [(15,158), (-23,68), (0,0), (56,0)]
cpa3 = [(56,0), (146,0), (158,225)]
cpa4 = [(158,225), (146,0), (203,0)]
fonta = [cpa1, cpa2, cpa3, cpa4]
cpl1 = [(0,0), (80,0), (200,270)]
cpl2 = [(200,270), (280,450), (293,608), (225,608)]
cpl3 = [(225,608), (180,608), (146,506), (124,338)]
cpl4 = [(124,338), (80,0), (225,0)]
fontl = [cpl1, cpl2, cpl3, cpl4]
# word & character origin (x, y) & scaling (x, y)
word = [fontv, fonti, fonts, fontu, fonta, fontl]
origin = [(-300, 0), (-180,0), (-90,0), (40,0), (170,0), (255,0)]
scale = [(1, 1), (0.4,0.4), (0.4,0.4), (0.4,0.4), (0.4,0.4), (0.4,0.4)]

# (skip)

# generate character
def gen_char(font, orgn, scaling):
    # generated character
    char = []
    # cp: control polygon
    for cp in font:
        # generated control plygon
        gcp = [[0] * 2 for i in range(len(cp))]
        for i in range(len(cp)):
            gcp[i][0] = cp[i][0] * scaling[0] + orgn[0]
            gcp[i][1] = cp[i][1] * scaling[1] + orgn[1]
        char.append(gcp)
    return(char)

# setup turtle
gamera = turtle.Turtle()
gamera.reset()
gamera.speed(0)
# plot word
for font, orgn, scaling in zip(word, origin, scale):
    char = gen_char(font, orgn, scaling)
    # plot character
    for cp in char:
        # draw control polygon
        draw_segments(gamera, cp, "black")
        
        # draw Bezier curve
        draw_bezier_subdiv(gamera, cp, "red")

# wait for the user to close the window
turtle.mainloop()