Kody źródłowe/Krzywa Béziera
Wygląd
Program przedstawiony poniżej potrafi narysować wielomianowe krzywe Béziera dowolnego stopnia, został napisany w języku Python. Domyślnie punkty kontrolne są losowane, przy jednym uruchomieniu generowane jest kilka krzywych. Liczbę krzywych, liczbę punktów kontrolnych i rozdzielczość obrazu można ustawić zmieniając wartości odpowiednich zmiennych.
Obliczenia są wykonywane w sposób "naiwny", wprost z definicji.
# -*- coding: iso-8859-2 -*-
#
# Program rysuje dowolną liczbę krzywych Beziera dowolnego stopnia.
# Do uruchomienia wymaga biblioteki PIL (Python Imaging Library).
newton_cache = {} # pamięć podręczna dla wyników funkcji newton
def Newton(n,k):
'''Funkcja oblicza wartość symbolu Newtona'''
global newton_cache
if (n,k) not in newton_cache:
# licznik = n*(n-1)*...*(n-k+1)
licznik = 1
for i in xrange(n-k+1, n+1):
licznik *= i
# mianownik = k!
mianownik = 1
for i in xrange(1, k+1):
mianownik *= i
newton_cache[(n,k)] = licznik/mianownik
return newton_cache[(n,k)]
def B(n,i,t):
'''
Funkcja oblicza wartość wielomianu bazowego Bernsteina dla
zadanego parametru t.
'''
return Newton(n,i) * (t**i) * (1.0-t)**(n-i)
def Bezier2D(punkty_kontrolne, k):
'''
Funkcja przybliża dwuwymiarową krzywą Beziera za pomocą łamanej
złożonej z k segmentów. Zwraca listę wierzchołków łamanej.
punkty_kontrolne - lista punktów kontrolnych: [(x0,y0), ..., (xn,yn)]
k - ilość segmentów
'''
n = len(punkty_kontrolne)-1 # stopień krzywej Beziera
# funkcja obliczająca współrzędne (x,y) punktu krzywej dla zadanego t
def p(t):
'''
x = \sum_{i=0}^n x_i B^n_i(t)
y = \sum_{i=0}^n y_i B^n_i(t)
'''
x = 0.0
y = 0.0
for i in xrange(n+1):
x += punkty_kontrolne[i][0]*B(n,i,t)
y += punkty_kontrolne[i][1]*B(n,i,t)
return (x,y)
dt = 1.0/k # krok parametru t
return [p(i*dt) for i in xrange(k+1)]
# program główny
if __name__ == '__main__':
import Image
import ImageDraw
# parametry programu
n = 15 # liczba punktów kontrolnych (stopień krzywej+1)
rozdzielczosc = 600 # rozdzielczość obrazów
k = 200 # liczba segmentów łamanej przybliżającej krzywą
l = 10 # liczba obrazów generowanych przy jednym
# uruchomieniu programu
image = Image.new("RGB", (rozdzielczosc, rozdzielczosc))
draw = ImageDraw.Draw(image)
from random import randint as R
for i in xrange(l):
print "Tworzenie krzywej %d z %d" % (i+1, l)
# 1. Wylosowanie n punktów kontrolnych
punkty_kontrolne = [(R(0,rozdzielczosc), R(0,rozdzielczosc)) for _ in xrange(n)]
# 2. Wyznaczenie łamanej p przyliżającą krzywą Beziera
p = Bezier2D(punkty_kontrolne, k)
# 3. Rysowanie krzywej:
# 3a. wyczyszczenie obrazu (kolorem białym)
draw.rectangle( [0,0, rozdzielczosc,rozdzielczosc], fill="#fff")
# 3b. rysowanie łamanej kontrolnej (w kolorze jasnoszarym)
draw.line(punkty_kontrolne, fill="#ccc")
# 3c. zaznaczenie niebieskimi kółkami punktów kontrolnych
r = 2 # promień
for (x,y) in punkty_kontrolne:
draw.ellipse([x-r,y-r, x+r,y+r], fill="#00f")
# 3d. rysowanie krzywej Beziera (w kolorze czerownym)
draw.line(p, fill="#f00")
# 4. Zapisanie obrazu do pliku
image.save("Krzywa-Beziera_%03d_%04d.png" % (n,i), "PNG")
Ten tekst nie podlega pod prawa autorskie. Jest zatem własnością publiczną, ponieważ jego autor udostępnił go na licencji public domain.