Code archives/Graphics/Cubic bezier curve function

This code has been declared by its author to be Public Domain code.

Download source code

Cubic bezier curve function by spacerat2009
Very simply put, ImaginaryHuman's code in http://www.blitzmax.com/codearcs/codearcs.php?code=1760 creates a fine bezier curve, but it's buried in the middle of the example and needs to be turned into a function to actually be of use. So I did just that, so now all you have to do is call BeizerPoints() with an array of points and you'll have another array returned to you. Not very much work I know, but I figured this would be more helpful to people looking to quickly implement beziers.

You might notice that I've kept the Point class from ImaginaryHuman's example. My reasoning behind that is that it's easier to manipulate an array of objects than an array of numbers.
'Cubic Bezier spline function
'Turned into a nifty function by Spacerat using code by ImaginaryHuman adapted from code by Wedoe

'Press Space for a totally new random spline
'Press left arrow to control the previous control point
'Press right arrow to control the next control point
'Press Escape to exit
'Move  mouse to see it adapt

Strict


Const Accuracy:Double=0.03		'Lower has more line segments
	
SeedRnd(MilliSecs())	'Different each time
SetGraphicsDriver GLMax2DDriver()
Graphics 640,480,0
SetBlend LIGHTBLEND
Local DoAnother:Int
Local ControlPoint:Int
glEnable(GL_LINE_SMOOTH)	'Quick antaliasing hack
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST)
glLineWidth(3.0)
Repeat
	DoAnother=False
	Local NumPoints:Int = Rand(3, 16)	'Whatever >3
	NumPoints=NumPoints-(NumPoints Mod 3)+1	'3 points per bezier plus 1, 4th point of each bez is shared
	Local Points:Point[NumPoints]
	For Local p:Int=0 To NumPoints-1
		Points[p]=New Point
		Points[p].x=Rand(20,620)
		Points[p].y=Rand(20,460)
	Next
	ControlPoint=NumPoints/2
	Repeat
		Cls
		Points[ControlPoint].x=MouseX()
		Points[ControlPoint].y=MouseY()
		'Draw controls
		For Local p:Int=0 To NumPoints-1
			SetColor $88,$88,$88
			DrawLine Points[p].x-7,Points[p].y-7,Points[p].x+7,Points[p].y+7
			DrawLine Points[p].x-7,Points[p].y+7,Points[p].x+7,Points[p].y-7
			SetColor $00,$44,$88
			DrawLine Points[p].x,Points[p].y,Points[Min(NumPoints-1,p+1)].x,Points[Min(NumPoints-1,p+1)].y
			DrawText p,Points[p].x+5,Points[p].y+5
		Next
		'Draw segments

		SetColor $FF, $FF, $FF
		
		Local b:Point[] = BeizerPoints(Points, Accuracy)
		
		DrawPoints(b)
		
		DrawText "Edges: " + String(b.dimensions()[0]), 0, 10
		DrawText "Controls: "+String(NumPoints),0,20
		DrawText "Curves: "+String(NumPoints/3),0,30
		Flip
		If KeyHit(KEY_SPACE) Then DoAnother=True
		If KeyHit(KEY_LEFT) Then ControlPoint=Max(0,ControlPoint-1)
		If KeyHit(KEY_RIGHT) Then ControlPoint=Min(NumPoints-1,ControlPoint+1)
	Until KeyHit(KEY_ESCAPE) Or DoAnother=True
Until DoAnother = False


'This will return an array of points on a bezier curve constructed with an array of points you supply it with

Function BeizerPoints:Point[] (Points:Point[], accuracy:Double = 0.02)
		Local bpoints:Point[Ceil((Points.Dimensions()[0] - 3) / Accuracy) ]
		Local p:Int = 0
		For Local S:Int = 0 To Points.Dimensions()[0] - 4 Step 3
			Local T:Double = 0
			While T <= 1
				Local X:Double = Points[s].x * (1 - T) ^ 3 + 3 * Points[s + 1].x * (1 - T) ^ 2 * T + 3 * Points[s + 2].x * (1 - T) * T ^ 2 + Points[s + 3].x * T ^ 3
				Local Y:Double = Points[s].y * (1 - T) ^ 3 + 3 * Points[s + 1].y * (1 - T) ^ 2 * T + 3 * Points[s + 2].y * (1 - T) * T ^ 2 + Points[s + 3].y * T ^ 3
				bpoints[p] = Point.Create(X, Y) 'There's probably a faster way of doing this, but this seemed like the most flexible way of doing it.
				p:+1
				T:+Accuracy
			Wend
		Next
		Return bpoints
End Function

Type Point
	Field x:Float
	Field y:Float
	Function Create:Point(x:Float, y:Float)
		Local n:Point = New Point
		n.x = x
		n.y = y
		Return n
	EndFunction
End Type

Function DrawPoints(dPoints:Point[])
	For Local p:Point = EachIn dpoints
		Plot(p.x, p.y)
	Next
End Function

Comments

None.

Code Archives Forum