Category Archives: graphics algorithms

Closed Catmull-Rom

Actionscript:
  1. var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
  2. addChild(new Bitmap(canvas));
  3.  
  4. var pnts:Array = new Array();
  5. // make control points
  6. for (var i:int = 0; i<5; i++){
  7.     var t:Number = i * 72 * Math.PI /180;
  8.     pnts.push(dot(200 + 100 * Math.cos(t),200 +100 * Math.sin(t)));  
  9. }
  10.  
  11. addEventListener(Event.ENTER_FRAME, onLoop);
  12. function onLoop(evt:Event):void {
  13.     canvas.lock();
  14.     canvas.fillRect(canvas.rect, 0x000000);
  15.     curve(pnts);
  16.     canvas.unlock();
  17. }
  18.  
  19. function tangent(pk1:Sprite, pk_1:Sprite){
  20.     return new Point((pk1.x - pk_1.x) / 2, (pk1.y - pk_1.y) / 2);
  21. }
  22.  
  23. // all math from http://en.wikipedia.org/wiki/Cubic_Hermite_spline
  24. function curve(p:Array, res:Number=.03):void{
  25.     var px:Number = 0;
  26.     var py:Number = 0;
  27.     var pIter:int = p.length - 1;
  28.     var m:Array = [];
  29.    
  30.     m[0] = tangent(p[1] ,  p[pIter]);
  31.     for (var i:int = 1; i<pIter; i++){
  32.         m[i] = tangent(p[i + 1], p[i - 1]);
  33.     }
  34.     m[pIter] = tangent(p[0],p[pIter-1]);
  35.    
  36.     for (var t:Number = 0; t <1; t+=res){
  37.          var t_2:Number = t * t;
  38.          var _1_t:Number = 1 - t;
  39.          var _2t:Number = 2 * t;
  40.          
  41.          var h00:Number =  (1 + _2t) * (_1_t) * (_1_t);
  42.          var h10:Number =  t  * (_1_t) * (_1_t);
  43.          var h01:Number =  t_2 * (3 - _2t);
  44.          var h11:Number =  t_2 * (t - 1);
  45.          
  46.          for (var k:int = 0; k <pIter; k++){
  47.              var k1:int = k + 1;
  48.              var pk:Sprite = p[k];
  49.              var pk1:Sprite = p[k1];
  50.              var mk:Point = m[k];
  51.              var mk1:Point = m[k1];
  52.              px = h00 * pk.x + h10 * mk.x + h01 * pk1.x + h11 * mk1.x;
  53.              py = h00 * pk.y + h10 * mk.y + h01 * pk1.y + h11 * mk1.y;
  54.              canvas.setPixel(px, py, 0xFFFFFF);
  55.          }
  56.           pk = p[k];
  57.           pk1 = p[0];
  58.           mk = m[k];
  59.           mk1= m[0];
  60.          
  61.           px = h00 * pk.x + h10 * mk.x + h01 * pk1.x + h11 * mk1.x;
  62.           py = h00 * pk.y + h10 * mk.y + h01 * pk1.y + h11 * mk1.y;
  63.           canvas.setPixel(px, py, 0xFFFFFF);
  64.     }
  65. }
  66.  
  67. // draggable dot
  68. function dot(xp:Number, yp:Number, col:uint = 0xFF0000, rad:Number=4):Sprite {
  69.     var s:Sprite = Sprite(addChild(new Sprite));
  70.     s.x = xp;
  71.     s.y = yp;
  72.     with(s.graphics) beginFill(col), drawCircle(0,0,rad);
  73.     s.buttonMode = true;
  74.     s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
  75.     return s;
  76. }
  77. function onDrag(evt:MouseEvent):void {
  78.     evt.currentTarget.startDrag()
  79. }
  80. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  81. function onUp(evt:MouseEvent):void{
  82.     stopDrag();
  83. }

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

Also posted in Math, setPixel | Tagged , | 2 Comments

k-th Order Catmull-Rom Spline

Actionscript:
  1. var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
  2. addChild(new Bitmap(canvas));
  3. var pnts:Array = new Array();
  4. // make 8 control points
  5. for (var i:int = 0; i<8; i++){
  6.     pnts.push(dot(50 + i * (30 + Math.random()*10),
  7.                              50 + i * (30 + Math.random()*10)));
  8. }
  9. addEventListener(Event.ENTER_FRAME, onLoop);
  10. function onLoop(evt:Event):void {
  11.     canvas.lock();
  12.     canvas.fillRect(canvas.rect, 0x000000);
  13.     curve(pnts);
  14.     canvas.unlock();
  15. }
  16. function tangent(pk1:Sprite, pk_1:Sprite){
  17.     return new Point((pk1.x - pk_1.x) / 2, (pk1.y - pk_1.y) / 2);
  18. }
  19. // all math from http://en.wikipedia.org/wiki/Cubic_Hermite_spline
  20. function curve(p:Array, res:Number=.03):void{
  21.     var px:Number = 0;
  22.     var py:Number = 0;
  23.     var pIter:int = p.length - 1;
  24.     var m:Array = [];
  25.     m[0] = tangent(p[1], p[0]);
  26.     for (var i:int = 1; i<pIter; i++){
  27.         m[i] = tangent(p[i + 1], p[i - 1]);
  28.     }
  29.     m[pIter] = tangent(p[pIter], p[pIter - 1]);
  30.     for (var t:Number = 0; t <1; t+=res){
  31.          var t_2:Number = t * t;
  32.          var _1_t:Number = 1 - t;
  33.          var _2t:Number = 2 * t;
  34.          var h00:Number =  (1 + _2t) * (_1_t) * (_1_t);
  35.          var h10:Number =  t  * (_1_t) * (_1_t);
  36.          var h01:Number =  t_2 * (3 - _2t);
  37.          var h11:Number =  t_2 * (t - 1);
  38.          for (var k:int = 0; k <pIter; k++){
  39.              var k1:int = k + 1;
  40.              var pk:Sprite = p[k];
  41.              var pk1:Sprite = p[k1];
  42.              var mk:Point = m[k];
  43.              var mk1:Point = m[k1];
  44.              px = h00 * pk.x + h10 * mk.x + h01 * pk1.x + h11 * mk1.x;
  45.              py = h00 * pk.y + h10 * mk.y + h01 * pk1.y + h11 * mk1.y;
  46.              canvas.setPixel(px, py, 0xFFFFFF);
  47.          }
  48.     }
  49. }
  50. // draggable dot
  51. function dot(xp:Number, yp:Number, col:uint = 0xFF0000, rad:Number=4):Sprite {
  52.     var s:Sprite = Sprite(addChild(new Sprite));
  53.     s.x = xp;
  54.     s.y = yp;
  55.     with(s.graphics) beginFill(col), drawCircle(0,0,rad);
  56.     s.buttonMode = true;
  57.     s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
  58.     return s;
  59. }
  60. function onDrag(evt:MouseEvent):void {
  61.     evt.currentTarget.startDrag()
  62. }
  63. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  64. function onUp(evt:MouseEvent):void{
  65.     stopDrag();
  66. }

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


Check it out here:

Also posted in Math, setPixel | Leave a comment

Catmull-Rom Spline

Actionscript:
  1. var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
  2. addChild(new Bitmap(canvas));
  3.  
  4. var p0:Sprite = dot(100, 100);
  5. var p1:Sprite = dot(120, 180);
  6. var p2:Sprite = dot(220, 180);
  7. var p3:Sprite = dot(250, 250);
  8.  
  9. addEventListener(Event.ENTER_FRAME, onLoop);
  10. function onLoop(evt:Event):void {
  11.     canvas.lock();  
  12.     canvas.fillRect(canvas.rect, 0x000000);
  13.  
  14.     curve(p0, p1, p2, p3);
  15.     canvas.unlock();
  16. }
  17.  
  18.  
  19. // all math from http://en.wikipedia.org/wiki/Cubic_Hermite_spline
  20. function curve(p0:Sprite, p1:Sprite, p2:Sprite, p3:Sprite, rez:Number=.02):void{
  21.     var px:Number = 0;
  22.     var py:Number = 0;
  23.     var m0:Point = tangent(p1, p0);
  24.     var m1:Point = tangent(p2, p0);
  25.     var m2:Point = tangent(p3, p1);
  26.     var m3:Point = tangent(p3, p2);
  27.    
  28.     for (var t:Number = 0; t <1; t+=rez){
  29.          var t_2:Number = t * t;
  30.          var _1_t:Number = 1 - t;
  31.          var _2t:Number = 2 * t;
  32.          
  33.          var h00:Number =  (1 + _2t) * (_1_t) * (_1_t);
  34.          var h10:Number =  t  * (_1_t) * (_1_t);
  35.          var h01:Number =  t_2 * (3 - _2t);
  36.          var h11:Number =  t_2 * (t - 1);
  37.          
  38.          px = h00 * p0.x + h10 * m0.x + h01 * p1.x + h11 * m1.x;
  39.          py = h00 * p0.y + h10 * m0.y + h01 * p1.y + h11 * m1.y;
  40.          canvas.setPixel(px, py, 0xFFFFFF);
  41.          
  42.          px = h00 * p1.x + h10 * m1.x + h01 * p2.x + h11 * m2.x;
  43.          py = h00 * p1.y + h10 * m1.y + h01 * p2.y + h11 * m2.y;
  44.          canvas.setPixel(px, py, 0xFFFFFF);
  45.          
  46.          px = h00 * p2.x + h10 * m2.x + h01 * p3.x + h11 * m3.x;
  47.          py = h00 * p2.y + h10 * m2.y + h01 * p3.y + h11 * m3.y;
  48.          canvas.setPixel(px, py, 0xFFFFFF);
  49.     }
  50. }
  51.  
  52. function tangent(pk1:Sprite, pk_1:Sprite){
  53.     return new Point((pk1.x - pk_1.x) / 2, (pk1.y - pk_1.y) / 2);
  54. }
  55.  
  56. // draggable dot
  57. function dot(xp:Number, yp:Number, col:uint = 0x507399, rad:Number=5):Sprite {
  58.     var s:Sprite = Sprite(addChild(new Sprite));
  59.     s.x = xp;
  60.     s.y = yp;
  61.     with(s.graphics) beginFill(col), drawCircle(0,0,rad);
  62.     s.buttonMode = true;
  63.     s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
  64.     return s;
  65. }
  66. function onDrag(evt:MouseEvent):void {
  67.     evt.currentTarget.startDrag()
  68. }
  69. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  70. function onUp(evt:MouseEvent):void{
  71.     stopDrag();
  72. }

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.

Also posted in Math, setPixel | Tagged , | 5 Comments

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.

Also posted in Math, setPixel | Tagged , | Leave a comment