Skip to content

Instantly share code, notes, and snippets.

@blzzua
Last active November 30, 2019 18:55
Show Gist options
  • Save blzzua/7640cd420960c01e0b252ef5584cd621 to your computer and use it in GitHub Desktop.
Save blzzua/7640cd420960c01e0b252ef5584cd621 to your computer and use it in GitHub Desktop.
bspline with out numpy
#import numpy as np
# cv = list of 2d control vertices
# n = number of samples (default: 100)
# d = curve degree (default: cubic = 3)
# closed = is the curve closed (periodic) or open? (default: open)
def bspline(cv, n=100, d=3, closed=False):
# Create a range of u values
count = len(cv)
knots = None
u = None
if not closed:
u = [ (float(i/(n-1)) * (count-d)) for i in range(0,n) ] # keep u=0 relative to 1st cv
knots = [0]*d + [ a for a in range(count-d+1)] + [count-d]*d
else:
u = [ ((float(i)/(n-1) * count) - (0.5 * (d-1))) % count for i in range(0,n) ] # keep u=0 relative to 1st cv
knots = [i for i in range(0-d,count+d+d-1) ]
# Simple Cox - DeBoor recursion
def coxDeBoor(u, k, d):
# Test for end conditions
if (d == 0):
if (knots[k] <= u and u < knots[k+1]):
return 1
return 0
Den1 = knots[k+d] - knots[k]
Den2 = knots[k+d+1] - knots[k+1]
Eq1 = 0;
Eq2 = 0;
if Den1 > 0:
Eq1 = ((u-knots[k]) / Den1) * coxDeBoor(u,k,(d-1))
if Den2 > 0:
Eq2 = ((knots[k+d+1]-u) / Den2) * coxDeBoor(u,(k+1),(d-1))
return Eq1 + Eq2
# Sample the curve at each u value
samples = [ [0,0] for i in range(n) ]
for i in range(n):
if not closed:
if u[i] == count-d:
samples[i] = cv[-1]
else:
for k in range(count):
coxDeBoor_factor = coxDeBoor(u[i],k,d)
samples[i] = [ component[0] + coxDeBoor_factor * component[1]
for component in zip(samples[i],cv[k]) ]
else:
for k in range(count+d):
coxDeBoor_factor = coxDeBoor(u[i],k,d)
samples[i] = [ component[0] + coxDeBoor_factor * component[1]
for component in zip(samples[i],cv[k%count]) ]
return samples
if __name__ == "__main__":
from graph import *
cv = [[ 230, 195],
[ 380, 230],
[ 750, 187],
[ 630, 520],
[ 427, 790],
[ 260, 507],
[ 183, 308],
[ 145, 200]]
canvasSize(900,900)
windowSize(900,900)
for mult in [1,2,10]:
splined_cv = bspline(cv, n=len(cv) * mult , d=2, closed=True)
splined_cv = [ [v[0],v[1]] for v in splined_cv ]
orig_cv = [ [v[0],v[1]] for v in cv ]
brushColor("#dee9af"); penColor("black"); penSize(1)
polyline(splined_cv)
penColor("red"); penSize(2)
orig_cv.append(orig_cv[0])
polyline(orig_cv)
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment