Monthly Archives: April 2009

3D Hypocycloid Shape

Actionscript:
  1. var matrix:Matrix3D = new Matrix3D();
  2. var verts:Vector.<Number> = new Vector.<Number>();
  3. var pVerts:Vector.<Number> = new Vector.<Number>();
  4. var uvts:Vector.<Number> = new Vector.<Number>();
  5. const TWO_PI:Number=Math.PI * 2;
  6. var step:Number=.05;
  7.  
  8. var brush:BitmapData = new BitmapData(3, 2, true, 0x41FFFFFF);
  9. var n:Number=8;
  10. var xp:Number=0,yp:Number=0,a:Number=12,t:Number=0;
  11. for (var i:Number = 0; i<TWO_PI; i+=step) {
  12.     for (var j:Number = 0; j<TWO_PI; j+=step) {
  13.         // unoptimized for readability
  14.     var cosi:Number = a/n * ((n - 1) * Math.cos(i) + Math.cos(Math.abs((n - 1) * i)));
  15.     var sini:Number = a/n * ((n - 1) * Math.sin(i) - Math.sin(Math.abs((n - 1) * i)));
  16.     var cosj:Number = a/n * ((n - 1) * Math.cos(j) + Math.cos(Math.abs((n - 1) * j)));
  17.     var sinj:Number = a/n * ((n - 1) * Math.sin(j) - Math.sin(Math.abs((n - 1) * j)));
  18.         verts.push(cosi * cosj);
  19.         verts.push(sini * cosj);
  20.         verts.push(a * sinj);
  21.         pVerts.push(0),pVerts.push(0);
  22.         uvts.push(0),uvts.push(0),uvts.push(0);
  23.     }
  24. }
  25. var canvas:BitmapData=new BitmapData(400,400,false,0x000000);
  26. addChild(new Bitmap(canvas));
  27. var dx:Number=0;
  28. var dy:Number=0;
  29. addEventListener(Event.ENTER_FRAME, onLoop);
  30. function onLoop(evt:Event):void {
  31.     dx += (mouseX - dx)/4;
  32.     dy += (mouseY - dy)/4;
  33.     matrix.identity();
  34.     matrix.appendRotation(dy,Vector3D.X_AXIS);
  35.     matrix.appendRotation(dx,Vector3D.Y_AXIS);
  36.     matrix.appendTranslation(200, 200, 0);
  37.     Utils3D.projectVectors(matrix, verts, pVerts, uvts);
  38.     canvas.lock();
  39.     canvas.fillRect(canvas.rect, 0x000000);
  40.     var p = new Point();
  41.     for (var i:int = 0; i<pVerts.length; i+=2) {
  42.         p.x = pVerts[i];
  43.         p.y = pVerts[i + 1];
  44.         canvas.copyPixels(brush, brush.rect, p, null, null, true);
  45.     }
  46.     canvas.unlock();
  47. }

Taking the Hypocycloid stuff from yesterday into 3D...

Posted in 3D, BitmapData, Math | Tagged , | 6 Comments

Hypocycloid Spiral

Actionscript:
  1. x = stage.stageWidth / 2;
  2. y = stage.stageHeight / 2;
  3. // change n to alter number of spikes (cuspes)
  4. var n:Number = 8;
  5. var xp:Number = 0, yp:Number = 0, a:Number = 10, t:Number = 0;
  6.  
  7. graphics.lineStyle(0, 0x000000);
  8. addEventListener(Event.ENTER_FRAME, onLoop);
  9. function onLoop(evt:Event):void {
  10.     for (var i:int = 0; i<10; i++){
  11.       // unoptimized for simplicity and similarity to original equations from here:
  12.           // http://mathworld.wolfram.com/Hypocycloid.html
  13.       xp = a/n * ((n - 1) * Math.cos(t) + Math.cos(Math.abs((n - 1) * t)));
  14.       yp = a/n * ((n - 1) * Math.sin(t) - Math.sin(Math.abs((n - 1) * t)))  ;
  15.      
  16.       a *= 1.002;
  17.        if (t == 0){
  18.            graphics.moveTo(xp, yp);
  19.        }else{
  20.            graphics.lineTo(xp, yp);  
  21.        }
  22.        t += .1;
  23.     }
  24. }

This code draws a Hypocycloid with a radius that increments - this results in a spiral formation.

I got the math from mathworld... here.

Posted in Math | Tagged , | 2 Comments

Pendulums

Actionscript:
  1. var mouseSpeedX:Number = 0;
  2. var prevX:Number = 0;
  3.  
  4. var pends:Array = new Array();
  5. for (var i:int = 0; i<10; i++){
  6.        pends.push(makePendulum(100+ i * 40, 100, 15, 100 + i * 10));
  7. }
  8.  
  9. addEventListener(Event.ENTER_FRAME, onRun);
  10. function onRun(evt:Event):void {
  11.        // mouseSpeed
  12.        mouseSpeedX = prevX - mouseX;
  13.        prevX = mouseX;
  14.  
  15.        for (var i:int = 0; i<pends.length; i++) pends[i]();
  16. }
  17.  
  18. function makePendulum(xp:Number, yp:Number, rad:Number, leng:Number):Function {
  19.        var rot:Number = 0;
  20.        var rotDest :Number = 0;
  21.        var rotVel:Number = 0
  22.        var string:Shape = Shape(addChild(new Shape()));
  23.        var ball:Sprite = Sprite(addChild(new Sprite()));
  24.        ball.buttonMode = true;
  25.        with(ball.graphics) beginFill(0xFF0000), drawCircle(0,leng, rad);
  26.        ball.x = xp;
  27.        ball.y = yp;
  28.        string.x = ball.x;
  29.        string.y = ball.y;
  30.        ball.addEventListener(MouseEvent.ROLL_OVER,function(){
  31.              rotDest = mouseSpeedX;
  32.        });
  33.        return function(){
  34.            // force rotDest back to 0
  35.            rotDest *= .8;
  36.                // elasticity (hooke's)
  37.                rotVel += (-1.9 * (rot - rotDest) - rotVel) / 4;
  38.                rot += rotVel
  39.                ball.rotation = rot;
  40.                // draw string:
  41.                string.graphics.clear();
  42.                string.graphics.lineStyle(0,0);
  43.                var pnt:Point = ball.localToGlobal(new Point(0, leng))
  44.                string.graphics.curveTo(0, leng / 2, pnt.x - ball.x, pnt.y-ball.y);
  45.   }
  46. }

This is a variation on something I wrote in response to a student question. It creates a few pendulums that can be pushed with the mouse.

Posted in motion | Tagged , | 5 Comments

Dynamic Shapes

Actionscript:
  1. // build some functions:
  2. var redGradient:Function = sl(16, add(100, mult(5)));
  3.  
  4. // grid positioning
  5. var xPos:Function = add(50, mult(30, cInt(div(4))));
  6. var yPos:Function = add(50, mult(30, mod(4)));
  7.  
  8. // create some shapes:
  9. var shapes:Array = createShapes(this, 22, [["beginFill", 0xCCCCCC], ["drawCircle", 0, 0, 10], ["endFill"], ["lineStyle",1, redGradient], ["drawRect", -5, -5, 10, 10]], {x:yPos, y:xPos, rotation:mult(10)});
  10.                                                                  
  11. function createShapes(par:DisplayObjectContainer,  num:Number,
  12.                                          funcs:Array, props:Object):Array {
  13.     var shapes:Array = [];
  14.     for (var i:int = 0; i<num; i++){
  15.         shapes[i] = par.addChild(new Shape());
  16.         for (var j:int = 0; j<funcs.length; j++) {
  17.             var a:Array = funcs[j].concat();
  18.             for (var k:int = 0; k<a.length; k++){
  19.                 if (a[k] is Function){
  20.                     a[k] = a[k](i);
  21.                 }
  22.             }
  23.             for (var key:String in props){
  24.                 var v:* = props[key];
  25.                 if (v is Function){
  26.                   shapes[i][key] = v(i);
  27.                 }else{
  28.                   shapes[i][key] = v;
  29.                 }
  30.             }
  31.             shapes[i].graphics[a[0]].apply(shapes[i].graphics, a.slice(1));
  32.         }
  33.     }
  34.     return shapes;
  35. }
  36.  
  37. // function building blocks
  38. const F:Function = function(a:*):*{return a};
  39.  
  40. function cInt(f:Function=null):Function{
  41.     if (f == null) f = F;
  42.     return function(n:Number):Number {
  43.         return int(f(n));
  44.     }
  45. }
  46.  
  47. function mod(m:Number, f:Function=null):Function{
  48.     if (f == null) f = F;
  49.     return function(n:Number):Number {
  50.         return f(n) % m;
  51.     }
  52. }
  53.  
  54. function div(d:Number, f:Function=null):Function{
  55.     if (f == null) f = F;
  56.     return function(n:Number):Number {
  57.         return f(n) / d;
  58.     }
  59. }
  60.  
  61. function mult(scalar:Number, f:Function=null):Function{
  62.     if (f == null) f = F;
  63.      return function(n:Number):Number {
  64.         return f(n) * scalar;
  65.     }
  66. }
  67.  
  68. function add(off:Number, f:Function=null):Function{
  69.      if (f == null) f = F;
  70.      return function(n:Number):Number {
  71.         return f(n) + off;
  72.     }
  73. }
  74. // shift left
  75. function sl(amount:int, f:Function=null):Function{
  76.      if (f == null) f = F;
  77.      return function(n:Number):Number {
  78.         return f(n) <<amount
  79.     }
  80. }

This is an unusual snippet I wrote a couple weeks back.... not sure where I was going with this really... has some interesting ideas in it.

Posted in misc | Tagged , | Leave a comment

Object Argument w/ Defaults

Actionscript:
  1. var boxDefaults:Object = {x:10, y:10, width:100, height:100, lineThickness:0, lineColor:0x000000, lineAlpha:1, fillColor:0xCCCCCC, fillAlpha:1}
  2. function drawBox(params:Object=null):void {
  3.     var p:Object=setDefaults(boxDefaults, params);
  4.     graphics.lineStyle(p.lineThickness, p.lineColor, p.lineAlpha);
  5.     graphics.beginFill(p.fillColor, p.fillAlpha);
  6.     graphics.drawRect(p.x, p.y, p.width, p.height);
  7. }
  8.  
  9. function setDefaults(defaults:Object, params:Object=null):Object {
  10.     if (params==null) {
  11.         params = new Object();
  12.     }
  13.     for (var key:String in defaults) {
  14.         if (params[key]==null) {
  15.             params[key]=defaults[key];
  16.         }
  17.     }
  18.     return params;
  19. }
  20.  
  21. // test it out... notice that all object properties are optional and have default values                                         
  22. drawBox();
  23.  
  24. drawBox({x:200, y:200, lineColor:0xFF0000, lineThickness:2, fillColor:0xCCCC00});
  25.  
  26. drawBox({x:200, y:320, width:50, height:150, lineAlpha:0, fillColor:0x416CCF});

This is a technique I've been using recently... inspired by tweening engines. I find this to be suitable when a function or object constructor has lots and lots of arguments (80% of the time if I have a function or object constructor with too many arguments I re-think my design, but every now and then I use this technique).

Basically, the function or object constructor takes one argument of type Object - once passed into the function this Object argument is passed to the setDefault() function which populates it with any properties that it's missing - each property has a default value. As a result you end up with an easy to read function call with a variable number of arguments and well thought out default values.

This snippet just draws a box (not very interesting or usefull) - I wanted to showcase the technique using a simple function. As a real world example... I recently used this technique in a mini-library I created for use with Box2D... will be posting the library in the next few days.... it's a library for fast prototyping and custom rendering.

Posted in dynamic, functions | Tagged , | 3 Comments

Drawing Gears

Actionscript:
  1. const TWO_PI:Number=Math.PI*2;
  2. // x, y, max radius, notch number
  3. drawVerts(calcGear(200, 200, 50, 9));
  4.  
  5. drawVerts(calcGear(400, 200, 30, 3));
  6.  
  7. drawVerts(calcGear(300, 350, 30, 5));
  8.  
  9. drawVerts(calcGear(400,400, 30, 2));
  10.  
  11. function calcGear(x:Number, y:Number, maxRad:Number, s:int):Array {
  12.     var verts:Array = new Array();
  13.     var step:Number=TWO_PI / (s * 4);
  14.     var mod:Number=0;
  15.     for (var i:Number = 0; i<=TWO_PI; i+=step) {
  16.         var r:Number = (int(mod)%2+1) * maxRad;
  17.         mod+=.5;
  18.         verts.push(x + r * Math.cos(i));
  19.         verts.push(y + r * Math.sin(i));
  20.     }
  21.     return verts;
  22. }
  23.  
  24. // could  use draw path here instead;
  25. function drawVerts(verts:Array):void{
  26.     graphics.lineStyle(0,0x000000);
  27.     graphics.moveTo(verts[0], verts[1]);
  28.     for (var i:int = 2; i<verts.length; i+=2) {
  29.         graphics.lineTo(verts[i], verts[i + 1]);
  30.     }
  31.     graphics.lineTo(verts[0], verts[1]);
  32. }

Needed to draw some gear shapes today...

Posted in Graphics | Tagged , | Leave a comment

Plot of sinh()

Actionscript:
  1. x = stage.stageWidth / 2;
  2. y = stage.stageHeight / 2;
  3. scaleX = scaleY = 3;
  4.  
  5. var t:Number =-5;
  6. var xp:Number = 0;
  7. var yp:Number = 0;
  8.  
  9. addEventListener(Event.ENTER_FRAME, onLoop);
  10. function onLoop(evt:Event):void {
  11.      xp = t;
  12.      yp = sinh(t);
  13.      
  14.     graphics.lineStyle(0,0);
  15.     if (t == -5){
  16.         graphics.moveTo(xp, yp);
  17.     }else{
  18.         graphics.lineTo(xp, yp);
  19.     }
  20.      if (t> 5){
  21.          removeEventListener(Event.ENTER_FRAME, onLoop);
  22.      }
  23.      t+=.2;
  24. }
  25. function sinh(x:Number):Number{
  26.     return (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) * 0.5;
  27. }

Just a quick plot to test the sinh() function from a few days ago...

Posted in Math | Tagged , | Leave a comment

Relative Positioning

Actionscript:
  1. var size:Array = [1, 1.5, .5, 1, .4, 1, 1, 1, .2, 1.1]
  2. var boxes:Array = new Array();
  3. var spacing:Number = 4;
  4. var container:Sprite = Sprite(addChild(new Sprite()));
  5. container.x = container.y = 100;
  6.  
  7. for (var i:int = 0; i<size.length; i++){
  8.     var box:Sprite = makeBox();
  9.     var prev:int = i - 1;
  10.     box.scaleX= box.scaleY = size[i];
  11.     if (i == 0){
  12.         box.y = 10;
  13.     }else{
  14.         // here's the trick
  15.         // if you animate the height property you need to do this again and again:
  16.         box.y = boxes[prev].y + boxes[prev].height/2+ box.height/2 + spacing
  17.     }
  18.     boxes.push(box);
  19. }
  20.  
  21. function makeBox():Sprite{
  22.     var box:Sprite = Sprite(container.addChild(new Sprite()));
  23.     with (box.graphics) beginFill(0xFF0000), drawRect(-50,-10, 100, 20);
  24.     return box;
  25. }

Sometimes you need to position a bunch of Sprites or MovieClips that are different sizes - and you want to keep the spacing between them the same. This snippet shows a simple example of this.

For more info you could also do this tutorial that I wrote on learningactionscript3.com

Posted in UI, misc | Tagged , | Leave a comment

Shapevent Log (not a snippet)

Recently launched a new project over at shapevent.com. If your enjoy sketchbooks, drawings and interactive ugliness... have a look here:

Shapevent Log

Many of the techniques covered in the code on this website will be used in shapevent log entries... no rss feed yet, but I'll have one up for it in the next few days....

Posted in misc | Leave a comment

sinh & cosh

Actionscript:
  1. function sinh(x:Number):Number{
  2.     return (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) * 0.5;
  3. }
  4.  
  5. function cosh(x:Number):Number{
  6.     return (Math.pow(Math.E, x) + Math.pow(Math.E, -x)) * 0.5;
  7. }

Needed sinh and cosh today. Easy enough to create with existing math functions. If you needed more speed you could inline these and replace Math.E with 2.71828183.

Got the math over at wikipedia (as usual).

Posted in Math, misc | Tagged , | Leave a comment