ProcessingのcurveVertex()をAS3で(2)

posted by cheesepie on 2009.05.12, under actionscript3
30th

ということで前回の続き。

Catmull-Romスプライン曲線を描くためには、4つ以上制御点がいるので、curveVertex()の回数が4回目以上になったら、ラインを引くようにすればいい。
前回のsplineTo()もちょっと係数の辺りを修正した。

public function curveVertex( x:Number, y:Number ):void
{
  var p:Point = new Point(x, y);
  __splineVertex[__splineVertexCount] = p;
  __splineVertexCount++;

  if (__splineVertexCount >= 4) {
    var idx0:int = __splineVertexCount - 4;
    var idx1:int = __splineVertexCount - 3;
    var idx2:int = __splineVertexCount - 2;
    var p2:Point = __splineVertex[idx1];

    this.graphics.moveTo(p2.x, p2.y);
    splineTo(__splineVertex[idx0], p2, __splineVertex[idx2], p);
  }
}

public function splineTo( p0:Point, p1:Point, p2:Point, p3:Point ):void
{
  var t:Number = 0;
  var k:Number = 1.0 / splineSegments;
  for (var i:uint = 1; i <= splineSegments; i++) {
    t = i * k;
    lineTo(
      catmullRom(p0.x, p1.x, p2.x, p3.x, t),
      catmullRom(p0.y, p1.y, p2.y, p3.y, t)
    );
  }
}

curveVertex()を呼ぶたびに、__splineVertex[]にPointとしてプッシュ。
で、4回目以降ならsplineTo()で曲線を描画。

実際にProcessingと同じ見た目になるかどうかのテスト。
リファレンスの例をやってみた。

package
{
  import flash.display.Sprite;
  import flash.display.Graphics;
  import flash.display.StageAlign;
  import flash.display.StageScaleMode;
  import flash.geom.Point;
  import flash.events.Event;

  [SWF(backgroundColor = 0xffffff)]
  public class Main extends Sprite
  {
    private var g:Graphics;
    private var __splineVertex:Array;
    private var __splineVertexCount:uint;
    public var splineSegments:uint = 20;

    public function Main()
    {
      if (stage) {
        initialize();
      } else {
        addEventListener(Event.ADDED_TO_STAGE, initialize);
      }
    }

    private function initialize(e:Event = null):void
    {
      removeEventListener(Event.ADDED_TO_STAGE, initialize);

      // main process
      g = this.graphics;
      begin();
      curveVertex(84, 91);
      curveVertex(84, 91);
      curveVertex(68, 19);
      curveVertex(21, 17);
      curveVertex(32, 100);
      curveVertex(32, 100);
      end();

      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
    }

    private function begin( thickness:Number=1, color:uint=0x000000 ):void
    {
      __splineVertex = [];
      __splineVertexCount = 0;
      g.lineStyle(thickness, color);
    }

    private function end():void
    {
      __splineVertexCount = 0;
    }

    private function curveVertex( x:Number, y:Number ):void
    {
      var p:Point = new Point(x, y);
      __splineVertex[__splineVertexCount] = p;
      __splineVertexCount++;

      if (__splineVertexCount >= 4) {
        var idx0:int = __splineVertexCount - 4;
        var idx1:int = __splineVertexCount - 3;
        var idx2:int = __splineVertexCount - 2;
        var p2:Point = __splineVertex[idx1];

        g.moveTo(p2.x, p2.y);
        splineTo(__splineVertex[idx0], p2, __splineVertex[idx2], p);
      }
    }

    private function splineTo( p0:Point, p1:Point, p2:Point, p3:Point ):void
    {
      var t:Number = 0;
      var k:Number = 1.0 / splineSegments;
      for (var i:uint = 1; i <= splineSegments; i++) {
        t = i * k;
        g.lineTo(
          catmullRom(p0.x, p1.x, p2.x, p3.x, t),
          catmullRom(p0.y, p1.y, p2.y, p3.y, t)
        );
      }
    }

    private function catmullRom( p0:Number, p1:Number, p2:Number, p3:Number, t:Number ):Number
    {
      var v0:Number = (p2 - p0) * 0.5;
      var v1:Number = (p3 - p1) * 0.5;
      return (2*p1 - 2*p2 + v0 + v1)*t*t*t + (-3*p1 + 3*p2 - 2*v0 - v1)*t*t + v0*t + p1;
    }
  }
}

うん、リファレンスの絵と全く同じ。
思ったよりも長くなったなー。
とはいえ、これでいい感じに曲線が描けるようになりました。
Graphicsクラスを拡張して汎用的に使えるようにしようっと。

Comments are closed.

TrackBack URL :

pagetop