Monthly Archives: March 2009

Cubic Hermite Spline

Actionscript:
  1. var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
  2. addChild(new Bitmap(canvas));
  3.  
  4. // create some draggable dots
  5. var p0:Sprite = dot(100, 100);
  6. var p1:Sprite = dot(200, 200);
  7. var m0:Sprite = dot(200, 100, 0xFFFFFF, 3)
  8. var m1:Sprite = dot(100, 200, 0xFFFFFF, 3);
  9.  
  10. addEventListener(Event.ENTER_FRAME, onLoop);
  11. function onLoop(evt:Event):void {
  12.     canvas.fillRect(canvas.rect, 0x000000);
  13.     var px:Number = 0;
  14.     var py:Number = 0;
  15.     for (var t:Number = 0; t <1; t+=.01){
  16.         var t_2:Number = t * t;
  17.         var t_3:Number = t_2 * t;
  18.        
  19.         // some repetitive math for clarity
  20.         px = (2 * t_3  - 3 * t_2 + 1) * p0.x +(t_3 - 2 * t_2 + t) *
  21.                  m0.x + (-2 * t_3 + 3 * t_2) * p1.x + (t_3 - t_2) * m1.x;
  22.         py = (2 * t_3  - 3 * t_2 + 1) * p0.y +(t_3 - 2 * t_2 + t) *
  23.                  m0.y + (-2 * t_3 + 3 * t_2) * p1.y + (t_3 - t_2) * m1.y;
  24.         canvas.setPixel(px, py, 0xFF0000);
  25.     }
  26. }
  27. // draggable dot
  28. function dot(xp:Number, yp:Number, col:uint = 0x507399, rad:Number=5):Sprite {
  29.     var s:Sprite = Sprite(addChild(new Sprite()));
  30.     s.x = xp;
  31.     s.y = yp;
  32.     with(s.graphics) beginFill(col), drawCircle(0,0,rad);
  33.     s.buttonMode = true;
  34.     s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
  35.     return s;
  36. }
  37. function onDrag(evt:MouseEvent):void {
  38.     evt.currentTarget.startDrag()
  39. }
  40. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  41. function onUp(evt:MouseEvent):void{
  42.     stopDrag();
  43. }

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.

Posted in Math, graphics algorithms, setPixel | Tagged , | Leave a comment

more(nesting(functions(graphDrawing)));

Actionscript:
  1. [SWF(width=800, height=600)]
  2.  
  3. var canvas:Graphics;
  4. var graphData:Array = sineData();
  5.  
  6. var graph0:Shape = Shape(addChild(new Shape()));
  7. graph0.x = 50;
  8. graph0.y = 150;
  9.  
  10. var graph1:Shape = Shape(addChild(new Shape()));
  11. graph1.x = 400;
  12. graph1.y = 150;
  13.  
  14. var graph2:Shape = Shape(addChild(new Shape()));
  15. graph2.x = 50;
  16. graph2.y = 400;
  17.  
  18. // use graphData to draw 3 different looking graphs:
  19.  
  20. canvas = graph0.graphics;
  21. axis(lines(graphData));
  22.  
  23. canvas = graph1.graphics;
  24. axis(dots(graphData, 0xFF0000), 0xFFCC00, 2);
  25.  
  26. canvas = graph2.graphics;
  27. axis(dots(dots(lines(lines(graphData, 0xCCCCCC, 20))), 0x0022FF, 0, 4), 0xFF);
  28.  
  29.  
  30. // generate data
  31. function sineData():Array{
  32.     var dat:Array = new Array();
  33.     for (var i:int = 0; i<60; i++){
  34.         dat.push(new Point(i * 4,  (30 + i) * Math.sin(i * 24 * Math.PI/180)));
  35.     }            
  36.     return dat;
  37. }
  38.  
  39. // render lines
  40. function lines(dat:Array, col:uint=0x000000, thick:Number=0):Array{
  41.     canvas.lineStyle(thick, col);
  42.     canvas.moveTo(dat[0].x, dat[0].y)
  43.     for (var i:int = 1; i<dat.length; i++){
  44.          canvas.lineTo(dat[i].x, dat[i].y);
  45.     }
  46.     return dat;
  47. }
  48.  
  49. // render dots
  50. function dots(dat:Array, col:uint=0xFF0000, thick:Number=0, rad:Number=1.5):Array{
  51.     canvas.lineStyle(thick, col);
  52.     for (var i:int = 0; i<dat.length; i++){
  53.          canvas.drawCircle(dat[i].x, dat[i].y, rad);
  54.     }
  55.     return dat;
  56. }
  57.  
  58. // render graph axis
  59. function axis(dat:Array, col:uint=0x000000, thick:Number=0):Array{
  60.     var d:Array = dat.concat();
  61.     d.sortOn("y", Array.NUMERIC);
  62.     var lastIndex:int = d.length - 1;
  63.     var minY:Number = d[0].y;
  64.     var maxY:Number = d[lastIndex].y;
  65.     d.sortOn("x", Array.NUMERIC);
  66.     var minX:Number = d[0].x;
  67.     var maxX:Number = d[lastIndex].x;
  68.     canvas.lineStyle(thick, col, .2);
  69.     canvas.moveTo(minX, 0);
  70.     canvas.lineTo(maxX, 0);
  71.     canvas.lineStyle(thick, col);
  72.     canvas.moveTo(minX, minY);
  73.     canvas.lineTo(minX, maxY);
  74.     canvas.lineTo(maxX, maxY);
  75.     return dat;
  76. }

This is something I've been meaning to post for awhile. Finally had time to write it today... It contains functions that are designed to be nested for the purpose of rendering a small data set in a few different ways...

The upper left image is rendered with axis labels and lines... and it defaults to the color black (line 21):

axis(lines(graphData));

The upper right image is rendered with yellow axis and red dots (line 24):

axis(dots(graphData, 0xFF0000), 0xFFCC00, 2);

etc... (line 27)
axis(dots(dots(lines(lines(graphData, 0xCCCCCC, 20))), 0x0022FF, 0, 4), 0xFF);

Alternatively you could write each function call on one line:

lines(graphData, 0xCCCCCC, 20);
lines(graphData);
dots(graphData);
dots(graphData, 0x0022FF, 0, 4)
axis(graphData, 0xFF);

NOTE: If you think this post is insane, please read the warning page of this site...

Posted in Graphics, functions, misc | Tagged , | Leave a comment

Torus 3D

Actionscript:
  1. stage.frameRate = 30;
  2. const TWO_PI:Number = Math.PI * 2;
  3. var centerX:Number = 200;
  4. var centerY:Number = 200;
  5. var p:Array = new Array();
  6. var zpos:Number;
  7. var xpos:Number;
  8. var ypos:Number;
  9. var depth:Number;
  10. var canvas:BitmapData = new BitmapData(400,400,true,0xFF000000);
  11. addChild(new Bitmap(canvas));
  12.  
  13. var dy:Number = 0
  14. var dx:Number = 0;
  15.  
  16. addEventListener(Event.ENTER_FRAME, onLoop);
  17. function onLoop(evt:Event):void {
  18.     canvas.fillRect(canvas.rect, 0xFF000000);
  19.      
  20.      dx += (mouseX / 100 - dx)/12;
  21.      dy += (mouseY / 100 - dy)/12;
  22.      var xp:Number, yp:Number, zp:Number;
  23.      
  24.      canvas.lock();
  25.      for (var a:Number =0; a <TWO_PI; a+=.08){
  26.           for (var b:Number =0; b <TWO_PI; b+=.08){
  27.               xp = (70 + 40 * Math.cos(a)) * Math.cos(b) ;
  28.               yp = (70 + 40 * Math.cos(a)) * Math.sin(b);
  29.               zp =  40 * Math.sin(a);
  30.               calc3D(xp, yp, zp, dx, dy);
  31.               convert3D();
  32.               canvas.setPixel(p[0], p[1], 0xFFFFFF);
  33.           }
  34.      }
  35.      canvas.unlock();
  36. }
  37. function calc3D(px:Number, py:Number, pz:Number, rotX:Number=0, rotY:Number=0):void {
  38.     // I first learned this from code by Andries Odendaal - www.wireframe.co.za
  39.     zpos=pz*Math.cos(rotX)-px*Math.sin(rotX) ;
  40.     xpos=pz*Math.sin(rotX)+px*Math.cos(rotX) ;
  41.     ypos=py*Math.cos(rotY)-zpos*Math.sin(rotY) ;
  42.     zpos=py*Math.sin(rotY)+zpos*Math.cos(rotY);
  43. }
  44. function convert3D():void {
  45.     depth = 1/((zpos/200)+1);
  46.     p[0] =  xpos * depth + centerX;
  47.     p[1] =  ypos * depth + centerY;
  48. }

This code draws a rotating 3D torus using setPixel().

Posted in 3D, BitmapData | Tagged , | Leave a comment

Flashvars

Actionscript:
  1. // variable is passed into the swf via Javascript (most likely swfObject)
  2. // myswf.swf?myFlashVar="a new value"
  3.  
  4. var myFlashVar:String = "Some Default Value";
  5. if (root.loaderInfo.parameters.myFlashVar){
  6.    myFlashVar = root.loaderInfo.parameters.myFlashVar;
  7. }

Getting at flashvars in AS3 requires a bit more typing than it did in AS2. Above is a technique I find myself using from time to time. Usually for paths to xml or dynamic callouts (large buttons with text, an image and a link that change frequently).

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