Page 1 of 1

n-degree Bézier curves

Posted: Fri Aug 07, 2015 6:56 am
by Henko
In Ricardobyte's thread "Poly Designer", a 3-degree Bezier function is proposed to do curve fitting over pictures.
Here is a generalization to n-degree curves, which allows more complex curves.
Just for the interested.

Code: Select all

' Testprogram for bezier curve function
' a n-degree bezier curve has n+1 control points: 2 end points and
'    n-1 "handles" that control the shape of the curve.
' To try different degrees: modify the variable "degree" and modify
'    the READ DATA  construct accordingly.
' Bezier curves can easily be rotated, scaled, and translated. See
'    Ricardobyte's thread "Poly Designer" for more on this.
'
' Move the control points slowly in order to keep tracking
'
option angle degrees ! option base 0
graphics ! graphics clear ! refresh off
draw color 0,0,0

degree=4
np=degree+1
dim cp(np,2)
for i=0 to degree ! READ cp(i,0),cp(i,1) ! next i
DATA 100,200, 350,50, 200,200, 550,370, 150,300
goto go_on
loop: get touch 0 as x,y
if x=-1 then loop
for i=0 to degree
  if (x-cp(i,0))^2 + (y-cp(i,1))^2 < 300 then
    cp(i,0)=x ! cp(i,1)=y ! goto go_on
    end if
  next i
go_on: graphics clear
bezier(degree,cp,30,3)
goto loop
end

' draw n-degree bézier curve (option base 0) assumed)
' deg is the degree of the curve
' cp contains x and y of end points and handles
' cp(0) and cp(deg) are the endpoints, handles in between.
' steps is the number of line segments used to draw the curve
' pen is the line thickness
'
def bezier(deg,cp(,),steps,pen)
np=deg+1       ' calculate factorial table and "n over k" table
dim fac(np),nok(np),p(np,2)
fac(0)=1 ! for i=1 to deg ! fac(i)=i*fac(i-1) ! next i
for i=0 to deg ! nok(i)=fac(deg)/fac(deg-i)/fac(i) ! next i
for i=0 to deg ! p(i,0)=cp(i,0) ! p(i,1)=cp(i,1) ! next i

draw size 3 ! fill color 0,0,1    ' draw end points and handles
fill circle p(0,0),p(0,1) size 5
fill circle p(deg,0),p(deg,1) size 5
for i=1 to deg-1 ! draw circle p(i,0),p(i,1) size 5 ! next i
draw size 1 ! draw alpha .3
draw line p(0,0),p(0,1) to p(1,0),p(1,1)
draw line p(deg,0),p(deg,1) to p(deg-1,0),p(deg-1,1)
draw size pen ! draw alpha 1
                                   ' draw the curve 
t=0 ! dt=1/steps ! draw size pen ! draw to p(0,0),p(0,1)
for i=1 to steps
  t+=dt ! tm=1-t ! x=0 ! y=0 ! a=tm^deg ! b=1
  for j=0 to deg
    f=nok(j)*a*b ! x+=f*p(j,0) ! y+=f*p(j,1)
    a/=tm ! b*=t
    next j
  draw line to x,y
  next i
refresh
end def


Re: n-degree Bézier curves

Posted: Sat Aug 08, 2015 3:03 pm
by Dutchman
Thanks for this code. I needed it, degree-3 was not sufficient for the program which I'm developing. :D
I have made some changes (indicated in the program by ****):
- xy-coordinates are modified to complex numbers
- touch handling is improved, so that points can be moved across or close to other points. (subroutine 'SetPoints')
- start values are randomly generated so that every degree can be tested.

I tested it up to degree 10. It turns out however that degrees higher then 5 does not make sense, or I don't see the real value :?
IF you don't mind, I will add this program to my 'Curves'-folder on Dropbox.
The screenshot is for degree=6.

Code: Select all

'Bezier n-degree cplx
' Testprogram for n-degree bezier curve function
'by Henko, august 7, 2015
'**** modified by Dutchman
'**** operating on complex coordinates x+y*1i
'NEW: arrays 'fac' and 'nok' only calculated if degree changes
'		array p() directly in arguments-list instead of copy from cp
'		arrays changed to OPTION BASE 1
'		'deg' removed from argumentslist
'
' a n-degree bezier curve has n+1 control points: 2 end points and
'    n-1 "handles" that control the shape of the curve.
' To try different degrees: modify the variable "degree" and modify
'    the READ DATA  construct accordingly.
' Bezier curves can easily be rotated, scaled, and translated. See
'    Ricardobyte's thread "Poly Designer" for more on this.
'
'**** User settings
margin=30 '**** touch margin
degree=4  '**** tested to 10
'
'---- Options and presets
OPTION ANGLE DEGREES
OPTION BASE 1 '*** fits better to counting: for 1 to np
GRAPHICS ! GRAPHICS CLEAR ! REFRESH OFF
DRAW COLOR 0,0,0
GET SCREEN SIZE sw,sh
'
'---- initialise
BezierN.deg=degree
np=degree+1
DIM cp(np)
xmax=0 ! ymax=0
'**** start with random complex numbers
FOR i=1 TO np 
  cp(i)=20+i*RND(10)+50*i%2+RND(100)+(50+10*i+i*RND(10))*1i
  xmax=MAX(xmax,REAL(cp(i))) ! ymax=MAX(ymax,IMAG(cp(i))) 
NEXT i
'**** scale  to reasonable size
SCALE=MAX(sw/xmax,sh/ymax)/2
FOR i=1 TO np ! cp(i)*=SCALE ! NEXT i
'
'==== main loop
GOTO go_on
LOOP: GET TOUCH 0 AS x,y
IF x=-1 THEN LOOP
xy=x+y*1i
GOSUB SetPoints
Go_on:
GRAPHICS CLEAR
REFRESH OFF
  BezierN(cp,30,3)
REFRESH
GOTO LOOP
END
'
'=========== Subroutines and functions
SetPoints: '***** start at previous touch
  n=0 'points checked
  IF catch>0 THEN
    i=catch ! catch=0 'catch' was active point
  ELSE ! i=1 ! ENDIF
  DO
    IF ABS(xy-cp(i)) < margin THEN
      catch=i ! cp(i)=xy
      RETURN
    ENDIF
    i=i%np+1 ! n+=1
  UNTIL catch>0 OR n=np
RETURN

'---- BezierN-function
' draw n-degree bézier curve (option base 0) assumed)
' deg is the degree of the curve
' cp contains x and y of end points and handles
' cp(0) and cp(deg) are the endpoints, handles in between.
' steps is the number of line segments used to draw the curve
' pen is the line thickness
'
DEF BezierN(p(),steps,pen)
' calculate factorial table and "n over k" table
IF deg<> OldDeg THEN
  np=deg+1
  DIM fac(np),nok(np)
  fac(1)=1 ! FOR i=2 TO np ! fac(i)=(i-1)*fac(i-1) ! NEXT i
  FOR i=1 TO np ! nok(i)=fac(np)/fac(np-i+1)/fac(i) ! NEXT i
  OldDeg=deg
ENDIF
'---- Draw np points 
DRAW SIZE 3 ! FILL COLOR 0,0,1    ' draw end points and handles
FILL CIRCLE REAL(p(1)),IMAG(p(1)) SIZE 5
FILL CIRCLE REAL(p(np)),IMAG(p(np)) SIZE 5
FOR i=2 TO np-1 ! DRAW CIRCLE REAL(p(i)),IMAG(p(i)) SIZE 5 ! NEXT i
'---- draw handles
DRAW SIZE 1 ! DRAW ALPHA .3
DRAW LINE REAL(p(1)),IMAG(p(1)) TO REAL(p(2)),IMAG(p(2))
DRAW LINE REAL(p(np)),IMAG(p(np)) TO REAL(p(np-1)),IMAG(p(np-1))
DRAW SIZE pen ! DRAW ALPHA 1
'---- Draw the curve 
t=0 ! dt=1/steps ! DRAW SIZE pen
DRAW TO REAL(p(1)),IMAG(p(1)) 'first point
FOR i=1 TO steps-1
  t+=dt ! tm=1-t ! xy=0 ! a=tm^deg ! b=1
  FOR j=1 TO np
    f=nok(j)*a*b ! xy+=f*p(j)
    a/=tm ! b*=t
  NEXT j
  DRAW LINE TO REAL(xy),IMAG(xy)
NEXT i
DRAW LINE TO REAL(p(np)),IMAG(p(np)) 'last point
END DEF
screenshot degree-6.PNG
screenshot degree-6.PNG (592.25 KiB) Viewed 2915 times

Re: n-degree Bézier curves

Posted: Sat Aug 08, 2015 7:28 pm
by Henko
Dutchman wrote:Thanks for this code. I needed it, degree-3 was not sufficient for the program which I'm developing. :D
I have made some changes (indicated in the program by ****):
- xy-coordinates are modified to complex numbers
- touch handling is improved, so that points can be moved across or close to other points. (subroutine 'SetPoints')
- start values are randomly generated so that every degree can be tested.

I tested it up to degree 10. It turns out however that degrees higher then 5 does not make sense, or I don't see the real value :?
IF you don't mind, I will add this program to my 'Curves'-folder on Dropbox.
The screenshot is for degree=6.
Of course i don't mind. This is what a forum like this is meant for. ;) Indeed the touch mechanism was clumsy. And indeed the effectiveness of high degrees is minimal. But it is a nice and efficient curve mechanism, especially when applying transformations to the curve(s).

Re: n-degree Bézier curves

Posted: Sun Aug 09, 2015 3:42 pm
by rbytes
You both have mathematics understanding far beyond mine. I'm happy that you are willing to share it. :P

Re: n-degree Bézier curves

Posted: Sat Aug 15, 2015 6:41 pm
by Dutchman
In the function "BezierN(p(),steps,pen)" there was a chance on division by zero when calculating the last point.
I made a repair.
The last point is now drawn after the FOR-NEXT loop.