Plotting and Drawing a Bezier Curve

The code shown below takes four control points as input, plots 100 points along the corresponding cubic Bezier curve, and draws them onto an HTML5 canvas. To see the code in action, paste it into an HTML file and open that file in a web browser that runs JavaScript.

This algorithm renders a curve with very wide spacing between the points at either end of the curve and very narrow spacing in the middle. For this reason, it’s not really a good candidate for a graphics library. But it does illustrate how Bezier curves work, and may serve as a foundation for further work.

<html>
<body>
<script type='text/javascript'>

function BezierCurveTest()
{
	this.main = function()
	{
		var view = new View
		(
			Color.Instances.BlueHalf,
			new Coords(320, 240)
		);

		document.body.appendChild
		(
			view.htmlElementBuild()
		);

		view.drawBezier
		(
			Color.Instances.Red,
			new Array
			(
				new Coords(100, 100),
				new Coords(125, 150),
				new Coords(175, 150),
				new Coords(200, 100)
			)
		);		
	}
}

// classes

function Color(name, systemColor)
{
	this.name = name;
	this.systemColor = systemColor;
}
{
	Color.Instances = new (function()
	{
		this.Blue 	= new Color("Blue", "#0000ff");
		this.BlueHalf 	= new Color("BlueDark", "#000080");
		this.Cyan 	= new Color("Cyan", "#00ffff");
		this.Green 	= new Color("Green", "#00ff00");
		this.Purple	= new Color("Purple", "#ff00ff");
		this.Red 	= new Color("Red", "#ff0000");
		this.Yellow 	= new Color("Yellow", "#ffff00");
	})();
}

function Coords(x, y)
{
	this.x = x;
	this.y = y;
}
{
	// constants

	Coords.NumberOfDimensions = 2;
	
	// instance methods

	Coords.prototype.absolute = function()
	{
		this.x = Math.abs(this.x);
		this.y = Math.abs(this.y);

		return this;
	}

	Coords.prototype.add = function(other)
	{
		this.x += other.x;
		this.y += other.y;

		return this;
	}

	Coords.prototype.clone = function()
	{
		return new Coords(this.x, this.y);
	}

	Coords.prototype.divide = function(other)
	{
		this.x /= other.x;
		this.y /= other.y;

		return this;
	}

	Coords.prototype.equals = function(other)
	{
		return (this.x == other.x && this.y == other.y);
	}

	Coords.prototype.multiplyScalar = function(scalar)
	{
		this.x *= scalar;
		this.y *= scalar;

		return this;
	}

	Coords.prototype.overwriteWith = function(other)
	{
		this.x = other.x;
		this.y = other.y;

		return this;
	}

	Coords.prototype.subtract = function(other)
	{
		this.x -= other.x;
		this.y -= other.y;

		return this;
	}
}

function View(colorBackground, sizeInPixels)
{
	this.colorBackground = colorBackground;
	this.sizeInPixels = sizeInPixels;
}
{
	// instance methods

	View.prototype.htmlElementBuild = function(sceneToRender)
	{
		var canvas		= document.createElement("canvas");
		canvas.id		= "cameraViewCanvas";
		canvas.width		= this.sizeInPixels.x;
		canvas.height		= this.sizeInPixels.y;
		canvas.style.position	= "absolute";
		canvas.style.cursor 	= "crosshair";
		canvas.style.background = this.colorBackground.systemColor;

		this.graphics = canvas.getContext("2d");

		return canvas;
	}

	View.prototype.drawBezier = function(color, controlPoints)
	{
		var tStep = .01;
		var currentPos = new Coords(0, 0);
		var tempPos = new Coords(0, 0);

		for (var t = 0; t <= 1; t += tStep)
		{
			var tSquared = t * t;

			var oneMinusT = 1 - t;
			var oneMinusTSquared = oneMinusT * oneMinusT;
			
			currentPos.overwriteWith
			(
				controlPoints[0]
			).multiplyScalar
			(
				oneMinusT * oneMinusTSquared
			);
			
			currentPos.add
			(				
				tempPos.overwriteWith
				(
					controlPoints[1]
				).multiplyScalar
				(
					3 * t * oneMinusTSquared
				)
			)

			currentPos.add
			(				
				tempPos.overwriteWith
				(
					controlPoints[2]
				).multiplyScalar
				(
					3 * tSquared * oneMinusT
				)
			);

			currentPos.add
			(				
				tempPos.overwriteWith
				(
					controlPoints[3]
				).multiplyScalar
				(
					t * tSquared
				)
			);
			
			this.drawPixel
			(
				color,
				currentPos
			);
		}
	}

	View.prototype.drawPixel = function(color, pos)
	{
		this.graphics.fillStyle = color.systemColor;
		this.graphics.fillRect(pos.x, pos.y, 1, 1);		
	}
}

// run

new BezierCurveTest().main();

</script>
</body>
</html>
Advertisements
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s