Browse the notebook

Category: Math

Babylonian Method for Square Root

var xn:Number = 1;
var xn1:Number = 0
var square:Number =39;

trace("find the sqrt of ", square);
trace("Math.sqrt: ", Math.sqrt(square))

// no starting approximation, just try up to 35 iterations
for(var i:int = 0; i<35; i++){
	xn1 = .5 * (xn  + square / xn);
	if (xn1== xn){
		trace("other sqrt: ", xn1);
		break;
	}
	xn = xn1;
}
/*outputs
find the sqrt of  39
Math.sqrt:  6.244997998398398
other sqrt:  6.244997998398398
*/

I was reading about calculating square roots – not for speed optimization purposes, just to see some of the different ways to go about it. The above snippet uses the Babylonian method to find the square root of a number. I left out the first step of guessing at the square root… so this snippet is by no means efficient…

Read snippet: Babylonian Method for Square Root

Supershapes / Superformula

// Superformula (equations from):
// http://www.geniaal.be/downloads/AMJBOT.pdf
// http://en.wikipedia.org/wiki/Superformula
const TWO_PI:Number = Math.PI * 2;
function superShape(a:Number, b:Number, m:Number, n1:Number, n2:Number, n3:Number, pnt:Point, scale:Number):void{
	var r:Number = 0
	var p:Number = 0;
	var xp:Number = 0, yp:Number = 0;
	while(p <= TWO_PI){
		var ang:Number = m * p / 4;
		with(Math){
			r = pow(pow(abs(cos(ang) / a), n2) + pow(abs(sin(ang) / b), n3),-1/n1);
			xp = r * cos(p);
			yp = r * sin(p);
		}
		p += .01;
		canvas.setPixel(pnt.x + xp *scale, pnt.y + yp * scale,  0xFFFFFF);
	 }
}
// test it out:
var canvas:BitmapData = new BitmapData(700,600,false, 0x000000);
addChild(new Bitmap(canvas, "auto", true));
 
superShape(1, 1, 5, 23, 23, 23, new Point(100,80), 30);
superShape(1, 1, 5, 13, 13, 3, new Point(200,80), 30);
superShape(1, 1, 8, 3, 13, 3, new Point(300,80), 30);
superShape(10,8, 16, 30, 13, 3, new Point(450,80), 30);
superShape(1,1, 1, .5, .5, .5, new Point(100,190), 100);

for (var i:int = 0; i <150; i++){
  superShape(1,1, 2, 1+i/800, 4, 8-i * .1, new Point(550,350), 50);
}
for (i = 0; i <20; i++){
  superShape(1.1,1.2, 6, 2 + i , 4, 9 - i, new Point(200,350), 50);
}

The above snippet demos a function that will draw Supershapes using the Superformula…

From wikipedia:
The Superformula appeared in a work by Johan Gielis. It was obtained by generalizing the superellipse, named and popularized by Piet Hein…

Here is the result of the above code:


You can read more about the Superformula here in the original paper by Gielis.

wikipedia entry…

3d Supershapes by Paul Bourke

Read snippet: Supershapes / Superformula

Tooth Curve (modified Bicuspid)

var canvas:BitmapData=new BitmapData(400,400,false,0xCCCCCC);
addChild(new Bitmap(canvas));

var a:Number=-1.21;
var r:Rectangle=new Rectangle(0,0,3,5);
var halfWidth:Number=canvas.width/2;
var halfHeight:Number=canvas.height/2;

render();

function render():void{
	for (var x:Number = -2; x<=2; x+=.05) {
		for (var y:Number = -2; y<=2; y+=.05) {
	
			// equation from : http://en.wikipedia.org/wiki/Bicuspid_curve
			//(x^2 - a^2) * (x - a)^2 + (y^2 - a^2) * (y^2 - a^2) = 0
	
			// unpoptimized:
			// var e:Number = (x*x - a*a) * (x-a)*(x-a) + (y*y-a*a) * (y*y-a*a);  
			// optimized:
			var x_a:Number=x-a;
			// factoring: x^2 - a^2 = (x + a) * (x - a)
			var y2_a2:Number =  (y + a) * (y - a);
			var e:Number = (x + a) * x_a * x_a * x_a +  y2_a2 * y2_a2;
	
			// tolerance beetween .7 & -.1;
			if (e<.7&&e>-.1) {
				r.x=halfWidth+y*50;
				r.y=halfHeight-x*100;
				canvas.fillRect(r, 0x000000);
			}
		}
	}
}

I’ve been looking for a single math equation to draw a tooth for sometime…. today I stumbled upon this… and realized it could probably be changed to look more like a tooth.

This snippet will draw this:

I’m using a graphing method here that allows me to use the Cartesian form of the equation and not the parameteric… I’ll explain a bit more about this in a later post.

Read snippet: Tooth Curve (modified Bicuspid)

Closed Catmull-Rom

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));

var pnts:Array = new Array();
// make control points
for (var i:int = 0; i<5; i++){
	var t:Number = i * 72 * Math.PI /180;
	pnts.push(dot(200 + 100 * Math.cos(t),200 +100 * Math.sin(t)));   
}

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	curve(pnts);
	canvas.unlock();
}

function tangent(pk1:Sprite, pk_1:Sprite){
	return new Point((pk1.x - pk_1.x) / 2, (pk1.y - pk_1.y) / 2);
}

// all math from http://en.wikipedia.org/wiki/Cubic_Hermite_spline
function curve(p:Array, res:Number=.03):void{
	var px:Number = 0;
    var py:Number = 0;
	var pIter:int = p.length - 1;
	var m:Array = [];
	
	m[0] = tangent(p[1] ,  p[pIter]);
	for (var i:int = 1; i<pIter; i++){
		m[i] = tangent(p[i + 1], p[i - 1]);
	}
	m[pIter] = tangent(p[0],p[pIter-1]);
	
	for (var t:Number = 0; t < 1; t+=res){
		 var t_2:Number = t * t;
		 var _1_t:Number = 1 - t;
		 var _2t:Number = 2 * t;
		 
		 var h00:Number =  (1 + _2t) * (_1_t) * (_1_t);
		 var h10:Number =  t  * (_1_t) * (_1_t);
		 var h01:Number =  t_2 * (3 - _2t);
		 var h11:Number =  t_2 * (t - 1);
		 
		 for (var k:int = 0; k < pIter; k++){
			 var k1:int = k + 1;
			 var pk:Sprite = p[k];
			 var pk1:Sprite = p[k1];
			 var mk:Point = m[k];
			 var mk1:Point = m[k1];
			 px = h00 * pk.x + h10 * mk.x + h01 * pk1.x + h11 * mk1.x;
			 py = h00 * pk.y + h10 * mk.y + h01 * pk1.y + h11 * mk1.y;
			 canvas.setPixel(px, py, 0xFFFFFF);
		 }
		  pk = p[k];
		  pk1 = p[0];
		  mk = m[k];
		  mk1= m[0];
		 
		  px = h00 * pk.x + h10 * mk.x + h01 * pk1.x + h11 * mk1.x;
		  py = h00 * pk.y + h10 * mk.y + h01 * pk1.y + h11 * mk1.y;
		  canvas.setPixel(px, py, 0xFFFFFF);
	}
}

// draggable dot
function dot(xp:Number, yp:Number, col:uint = 0xFF0000, rad:Number=4):Sprite {
	var s:Sprite = Sprite(addChild(new Sprite));
	s.x = xp;
	s.y = yp;
	with(s.graphics) beginFill(col), drawCircle(0,0,rad);
	s.buttonMode = true;
	s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
	return s;
}
function onDrag(evt:MouseEvent):void {
	evt.currentTarget.startDrag()
}
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onUp(evt:MouseEvent):void{
	stopDrag();
}

This a variation on a post from a few days ago. This shows how to create a closed Catmull Rom spline.

See the other Catmull-Rom related Posts

Read snippet: Closed Catmull-Rom

Hippopede

x=stage.stageWidth/2;
y=stage.stageHeight/2;
var xp:Number = 0, yp:Number = 0;
var r:Number = 0, t:Number = 0;
var speed:Number=.1;

var range:Number=.2;
var b:Number = 20;
var a:Number = b * range;
var orbit:Number = 2 * Math.PI + speed;
 
graphics.lineStyle(0,0x000000);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	var sin:Number=Math.sin(t);
	r =  Math.sqrt(4 * b * (a - b * (sin * sin)));
	xp= r * Math.cos(t);
	yp= r * sin;
	
    if (t==0) {
		graphics.moveTo(xp, yp);
	} else {
		graphics.lineTo(xp, yp);
	}

	t += speed;
	
	if (t > orbit) {
		range += .5;
		a= b * range;
		t= 0;
	}
}

The above draws a Hippopede

Read snippet: Hippopede

Fermat’s Spiral

x = stage.stageWidth / 2;
y = stage.stageHeight / 2;

var xp:Number = 0, yp:Number = 0;
var r:Number = 0, t:Number = 0;
var speed:Number = .07;
var scale:Number = 20;

var plot0:Shape = Shape(addChild(new Shape()));
var plot1:Shape = Shape(addChild(new Shape()));
plot0.graphics.lineStyle(0,0x000000);
plot1.graphics.lineStyle(0,0x000000);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	 r =  scale * Math.sqrt(t);
	 xp =  r * Math.cos(t);
	 yp =  r * Math.sin(t);
	 t += speed;
	 
	plot0.graphics.lineTo(xp, yp);
    plot1.graphics.lineTo(-xp, -yp);
}

This snippet draws Fermat’s Spiral.

Read snippet: Fermat’s Spiral

Interesting Function Composition

var multBy2Add3:Function = add(3, mult(2));

trace(multBy2Add3(10));
// 10 * 2  = 20
//  20 + 3 = 23

var add2AndSquare = sq(add(2));

trace(add2AndSquare(8));
// 8 + 2 = 10
// 10 * 10 = 100

var multBy2_3times:Function = repeat(3,mult(2));

trace(multBy2_3times(3));
// 3 * 2 = 6;
// 6 * 2 = 12;
// 12 * 2 = 24

// you can also chain for even less readability
trace(sq(mult(5,add(1)))(4));
// 4 + 1 = 5
// 5 * 5 = 25;
// 25 * 25 = 625;

/*
outputs: 
12
100
24
625
*/

// function  composition
const F:Function = function(a:*):*{return a};
function mult(scalar:Number, f:Function=null):Function{
	if (f == null) f = F;
	 return function(n:Number){
		return f(n) * scalar;
	}
}

function add(off:Number, f:Function=null):Function{
	 if (f == null) f = F;
	 return function(n:Number){
		return f(n) + off;
	}
}
function sq(f:Function=null):Function{
	 if (f == null) f = F;
	 return function(n:Number){
		 var v:Number = f(n);
		return  v * v;
	}
}
function repeat(times:int, f:Function):Function {
	 if (f == null) f = F;
	 return function (n:Number){
		 var v:Number = n;
		 for (var i:int = 0; i<times; i++) v = f(v);
		 return v;
	 }
}

The above shows some interesting function composition… this demo contains the following functions:

mult();
add();
sq();
repeat();

These functions are designed to be combined to create new functions.

Read snippet: Interesting Function Composition

k-th Order Catmull-Rom Spline

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));
var pnts:Array = new Array();
// make 8 control points
for (var i:int = 0; i<8; i++){
	pnts.push(dot(50 + i * (30 + Math.random()*10),
							 50 + i * (30 + Math.random()*10)));
}
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	curve(pnts);
	canvas.unlock();
}
function tangent(pk1:Sprite, pk_1:Sprite){
	return new Point((pk1.x - pk_1.x) / 2, (pk1.y - pk_1.y) / 2);
}
// all math from http://en.wikipedia.org/wiki/Cubic_Hermite_spline
function curve(p:Array, res:Number=.03):void{
	var px:Number = 0;
	var py:Number = 0;
	var pIter:int = p.length - 1;
	var m:Array = [];
	m[0] = tangent(p[1], p[0]);
	for (var i:int = 1; i<pIter; i++){
		m[i] = tangent(p[i + 1], p[i - 1]);
	}
	m[pIter] = tangent(p[pIter], p[pIter - 1]);
	for (var t:Number = 0; t <1; t+=res){
		 var t_2:Number = t * t;
		 var _1_t:Number = 1 - t;
		 var _2t:Number = 2 * t;
		 var h00:Number =  (1 + _2t) * (_1_t) * (_1_t);
		 var h10:Number =  t  * (_1_t) * (_1_t);
		 var h01:Number =  t_2 * (3 - _2t);
		 var h11:Number =  t_2 * (t - 1);
		 for (var k:int = 0; k <pIter; k++){
			 var k1:int = k + 1;
			 var pk:Sprite = p[k];
			 var pk1:Sprite = p[k1];
			 var mk:Point = m[k];
			 var mk1:Point = m[k1];
			 px = h00 * pk.x + h10 * mk.x + h01 * pk1.x + h11 * mk1.x;
			 py = h00 * pk.y + h10 * mk.y + h01 * pk1.y + h11 * mk1.y;
			 canvas.setPixel(px, py, 0xFFFFFF);
		 }
	}
}
// draggable dot
function dot(xp:Number, yp:Number, col:uint = 0xFF0000, rad:Number=4):Sprite {
	var s:Sprite = Sprite(addChild(new Sprite));
	s.x = xp;
	s.y = yp;
	with(s.graphics) beginFill(col), drawCircle(0,0,rad);
	s.buttonMode = true;
	s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
	return s;
}
function onDrag(evt:MouseEvent):void {
	evt.currentTarget.startDrag()
}
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onUp(evt:MouseEvent):void{
	stopDrag();
}

More Catmull-Rom stuff. This one can have any number of control points:


Check it out here:

Read snippet: k-th Order Catmull-Rom Spline

Catmull-Rom Spline

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));

var p0:Sprite = dot(100, 100);
var p1:Sprite = dot(120, 180);
var p2:Sprite = dot(220, 180);
var p3:Sprite = dot(250, 250);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.lock();   
	canvas.fillRect(canvas.rect, 0x000000);

	curve(p0, p1, p2, p3);
	canvas.unlock();
}


// all math from http://en.wikipedia.org/wiki/Cubic_Hermite_spline
function curve(p0:Sprite, p1:Sprite, p2:Sprite, p3:Sprite, rez:Number=.02):void{
	var px:Number = 0;
    var py:Number = 0;
	var m0:Point = tangent(p1, p0);
	var m1:Point = tangent(p2, p0);
	var m2:Point = tangent(p3, p1);
	var m3:Point = tangent(p3, p2);
	
	for (var t:Number = 0; t < 1; t+=rez){
		 var t_2:Number = t * t;
		 var _1_t:Number = 1 - t;
		 var _2t:Number = 2 * t;
		 
		 var h00:Number =  (1 + _2t) * (_1_t) * (_1_t);
		 var h10:Number =  t  * (_1_t) * (_1_t);
		 var h01:Number =  t_2 * (3 - _2t);
		 var h11:Number =  t_2 * (t - 1);
		 
		 px = h00 * p0.x + h10 * m0.x + h01 * p1.x + h11 * m1.x;
		 py = h00 * p0.y + h10 * m0.y + h01 * p1.y + h11 * m1.y;
		 canvas.setPixel(px, py, 0xFFFFFF);
		 
		 px = h00 * p1.x + h10 * m1.x + h01 * p2.x + h11 * m2.x;
		 py = h00 * p1.y + h10 * m1.y + h01 * p2.y + h11 * m2.y;
		 canvas.setPixel(px, py, 0xFFFFFF);
		 
		 px = h00 * p2.x + h10 * m2.x + h01 * p3.x + h11 * m3.x;
		 py = h00 * p2.y + h10 * m2.y + h01 * p3.y + h11 * m3.y;
		 canvas.setPixel(px, py, 0xFFFFFF);
	}
}

function tangent(pk1:Sprite, pk_1:Sprite){
	return new Point((pk1.x - pk_1.x) / 2, (pk1.y - pk_1.y) / 2);
}

// draggable dot
function dot(xp:Number, yp:Number, col:uint = 0x507399, rad:Number=5):Sprite {
	var s:Sprite = Sprite(addChild(new Sprite));
	s.x = xp;
	s.y = yp;
	with(s.graphics) beginFill(col), drawCircle(0,0,rad);
	s.buttonMode = true;
	s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
	return s;
}
function onDrag(evt:MouseEvent):void {
	evt.currentTarget.startDrag()
}
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onUp(evt:MouseEvent):void{
	stopDrag();
}

This is snippet draws a Catmull-Rom spline based on 4 control points. A nice feature of Catmull-Rom splines is that they always pass through each of their control points.


have a look at the swf here:

I first learned about Catmull-Rom splines somewhere in the processing forums.

I got all my info for this snippet from this wikipedia page.

There is a good deal of room for optimization here… I may post an optimized version in the future.

Read snippet: Catmull-Rom Spline

Cubic Hermite Spline

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));

// create some draggable dots
var p0:Sprite = dot(100, 100);
var p1:Sprite = dot(200, 200);
var m0:Sprite = dot(200, 100, 0xFFFFFF, 3)
var m1:Sprite = dot(100, 200, 0xFFFFFF, 3);

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.fillRect(canvas.rect, 0x000000);
	var px:Number = 0;
	var py:Number = 0;
	for (var t:Number = 0; t <1; t+=.01){
		var t_2:Number = t * t;
		var t_3:Number = t_2 * t;
		
		// some repetitive math for clarity
		px = (2 * t_3  - 3 * t_2 + 1) * p0.x +(t_3 - 2 * t_2 + t) *
				 m0.x + (-2 * t_3 + 3 * t_2) * p1.x + (t_3 - t_2) * m1.x;
		py = (2 * t_3  - 3 * t_2 + 1) * p0.y +(t_3 - 2 * t_2 + t) *
				 m0.y + (-2 * t_3 + 3 * t_2) * p1.y + (t_3 - t_2) * m1.y;
		canvas.setPixel(px, py, 0xFF0000);
	}
}
// draggable dot
function dot(xp:Number, yp:Number, col:uint = 0x507399, rad:Number=5):Sprite {
	var s:Sprite = Sprite(addChild(new Sprite()));
	s.x = xp;
	s.y = yp;
	with(s.graphics) beginFill(col), drawCircle(0,0,rad);
	s.buttonMode = true;
	s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
	return s;
}
function onDrag(evt:MouseEvent):void {
	evt.currentTarget.startDrag()
}
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onUp(evt:MouseEvent):void{
	stopDrag();
}

This is the start of my exploration of Cubic Hermite Splines (like Catmull–Rom)… I wrote this snippet while skimming the wikipedia article on the subject…. at first I wasn’t sure if this was correct, but I added tangent calculations for a Catmull-Rom and it worked nicely… will post that tomorrow.

Read snippet: Cubic Hermite Spline