Math and (Quasi) Physics in Action Script 3

Rotation around a center

This sample demonstrates two ways of ratating coordinate around a center point

The first example(P1 and C1) is straight forward while the second(P2 and C2) is more versatile and can be more efficent when treating more than one point in the same angle, in that case sine and cosine need to be computed only once before applied to each coordinate calculation of the points.

// P1 and C1 
var angle:Number = Math.atan2(P1.y - C1.y,  P1.x - C1.x);
var radius:Number = Point.distance(C1, P1);
P1.x = C1.x + Math.cos(angle + vr) * radius;
P1.y = C2.y + Math.sin(angle + vr) * radius;

// P2 and C2 
var distX:Number = P2.x - C2.x;
var distY:Number = P2.y - C2.y;
P2.x =  Math.cos(vr) * distX - Math.sin(vr) * distY + C2.x;
P2.y =  Math.cos(vr) * distY + Math.sin(vr) * distX + C2.y;

In action script 3, the Matrix class's rotate method works in the same way as the second example.

Main.as

package {
  import flash.display.*;
  import flash.events.*;
  import flash.geom.Point;
  public class Main extends PpGraphics {
    private var C1:PpObject, C2:PpObject, P1:PpObject, P2:PpObject;
    private var vr:Number = Math.PI / 180;
    public function Main() {
      
      origin(stage.stageWidth / 2,stage.stageHeight / 2);
      gCanvas.graphics.drawCircle(-100,0,80);
      gCanvas.graphics.drawCircle(100,0,80);
      
      P1 = new PpObject(-20,0);
      C1 = new PpObject(-100,0);
      P2 = new PpObject(180,0);
      C2 = new PpObject(100,0);
      circle(P1,4,C_MOVABLE, "P1");
      circle(C1,2,C_FIXED, "C1");
      circle(P2,4,C_MOVABLE, "P2");
      circle(C2,2,C_FIXED, "C2");
      path(P1, C1);
      path(P2, C2);
    }
    
    override protected function step():void {
      var angle:Number = Math.atan2(P1.y - C1.y,  P1.x - C1.x);
      var radius:Number = Point.distance(C1, P1);
      P1.x = C1.x + Math.cos(angle + vr) * radius;
      P1.y = C2.y + Math.sin(angle + vr) * radius;
      
      var distX:Number = P2.x - C2.x;
      var distY:Number = P2.y - C2.y;
      P2.x =  Math.cos(vr) * distX - Math.sin(vr) * distY + C2.x;
      P2.y =  Math.cos(vr) * distY + Math.sin(vr) * distX + C2.y;
    }
  }
}

PpGraphics.as

package {
  import flash.display.*;
  import flash.events.*;
  import flash.text.*;
  class PpGraphics extends Sprite {
    protected var canvas:Sprite;
    protected var gCanvas:Sprite;
    protected var tCanvas:Sprite;
    private var textout:TextField;
    private var shapeList:Array;
    private var pathList:Array;
    private var lineList:Array;
    private var dragTarget:Sprite = null;
    private var handleList:Array;
    private var left:Number, right:Number, top:Number, bottom:Number;
    
    protected const C_MOVABLE:uint = 0xFF6600;
    protected const C_DRAGGABLE:uint = 0x0066FF;
    protected const C_FIXED:uint = 0x000000;
    protected const C_GUIDE:uint = 0xAAAAAA;
    
    public function PpGraphics():void {
      pathList = new Array();
      lineList = new Array();
      shapeList = new Array();
      handleList = new Array();
      
      addChild(gCanvas = new Sprite());
      gCanvas.graphics.lineStyle(0, C_GUIDE, 0.5);
      addChild(canvas = new Sprite());
      addChild(tCanvas = new Sprite());
      addChild(textout = getTextout());
      addEventListener(Event.ENTER_FRAME,h_enterFrame0);
      addEventListener(Event.ENTER_FRAME,h_enterFrame1);
      addEventListener(Event.ENTER_FRAME,h_enterFrame2);
      origin(0,0);
    }
    protected function h_enterFrame0(evt:Event):void {
      updateDrag();
    }
    
    protected function h_enterFrame1(evt:Event):void {
      step();
    }
    
    protected function step():void {}
    
    private function h_enterFrame2(evt:Event):void {
      updateGraphics();
    }
    
    private function updateDrag():void {
      if (!dragTarget) { return }
      
      var item:Object;
      var i:uint;
      
      dragTarget.x = canvas.mouseX;
      dragTarget.y = canvas.mouseY;
      
      for (i = 0; i < handleList.length; i ++) {
        item = handleList[i];
        item.obj.x = item.sprite.x;
        item.obj.y = item.sprite.y;
      }
    }
        
    private function updateGraphics():void {
      var g:Graphics = canvas.graphics;
      var item:Object;
      var i:uint;
      
      for (i = 0; i < shapeList.length; i ++) {
        item = shapeList[i];
        item.sprite.x = item.obj.x;
        item.sprite.y = item.obj.y;
      }
      
      g.clear();
      for (i = 0; i < pathList.length; i ++) {
        item = pathList[i];
        g.lineStyle(item.w, item.col, 0.5);
        g.moveTo(item.obj1.x, item.obj1.y);
        g.lineTo(item.obj2.x, item.obj2.y);
      }

      for (i = 0; i < lineList.length; i ++) {
        item = lineList[i];
        
        var l:Pp2dLine = Pp2dLine.fromPoints(item.obj1.x, item.obj1.y, item.obj2.x, item.obj2.y);
        g.lineStyle(item.w, item.col, 0.5);
        
        if (l.slope == 0) {
          g.moveTo(left, item.obj1.y);
          g.lineTo(right, item.obj1.y);
        } else if (isNaN(l.slope)) {
          g.moveTo(item.obj1.x, top);
          g.lineTo(item.obj1.x, bottom);
        } else if (l.slope > 1 || l.slope < -1) {
          g.moveTo(l.yToX(top), top);
          g.lineTo(l.yToX(bottom), bottom);
        } else {
          g.moveTo(left, l.xToY(left));
          g.lineTo(right, l.xToY(right));
        }
      }
      
    }
    
    /*
    * origin
    */
    
    protected function origin(x,y):void {
      gCanvas.x = canvas.x = x;
      gCanvas.y = canvas.y = y;
      left = x - stage.stageWidth;
      right = stage.stageWidth - x;
      top = y - stage.stageHeight;
      bottom = stage.stageHeight - y;
    }
    
    /*
    * guide
    */
    
    protected function guide(x1:Number,y1:Number,x2:Number,y2:Number):void {
      var g:Graphics = gCanvas.graphics;
      g.moveTo(x1,y1);
      g.lineTo(x2,y2);
    }
    
    protected function guideLabel(x:Number,y:Number,str:String):void {
      var t:TextField = label(str, C_GUIDE);
      t.x = x;
      t.y = y;
      gCanvas.addChild(t);
    }
    
    
    /*
    * graphic items
    */
    
    protected function circle(obj:PpObject, radius:Number = 3, col:uint = C_FIXED,labelStr:String = "") {
      var s:Sprite = new Sprite();
      s.graphics.beginFill(col, 0.5);
      s.graphics.drawCircle(0,0,radius);
      s.graphics.endFill();
      if (labelStr.length > 0) {
        var l:TextField = label(labelStr,col);
        s.addChild(l);
      }
      return addShape(obj, s);
    }
    
    private function addShape(obj:PpObject,s:Sprite):Object {
      var item:Object = {obj:obj,sprite:s};
      s.x = obj.x;
      s.y = obj.y;
      canvas.addChild(s);
      shapeList.push(item);
      return item
    }
    
    protected function path(obj1:PpObject, obj2:PpObject,col:uint = C_MOVABLE, w:Number = 0):Object {
      var item:Object = {obj1:obj1,obj2:obj2,col:col,w:w};
      pathList.push(item);
      return item
    }

    protected function line(obj1:PpObject, obj2:PpObject,col:uint = C_MOVABLE, w:Number = 0):Object {
      var item:Object = {obj1:obj1,obj2:obj2,col:col,w:w};
      lineList.push(item);
      return item
    }

    /*
    * text
    */
    
    private function label(str:String, col:uint):TextField {
      var t:TextField = new TextField();
      var tf:TextFormat = new TextFormat();
      t.autoSize = TextFieldAutoSize.LEFT;
      t.selectable = false;
      tf.font = "_sans";
      tf.color = col;
      t.defaultTextFormat = tf;
      t.text = str;
      return t;
    }
    
    private function getTextout():TextField {
      var t:TextField = new TextField();
      var tf:TextFormat = new TextFormat();
      t.width = stage.width - 20;
      t.height = stage.height - 20;
      t.x = t.y = 10;
      t.multiline = true;
      t.autoSize = TextFieldAutoSize.LEFT;
      t.selectable = false;
      tf.font = "_sans";
      tf.color = C_GUIDE;
      t.defaultTextFormat = tf;
      return t;
    }
    
    protected function print(str:String):void {
      textout.appendText(str + "\n");
    }
    protected function clearText():void {
      textout.text = "";
    }
    
    
    /*
    * drag
    */
    
    protected function enableDrag(...args):void {
      var s:Sprite;
      var item:Object;
      for (var i:uint = 0; i < args.length; i ++) {
        for (var j:uint = 0; j < shapeList.length; j ++) {
          if (shapeList[j].obj == args[i]) { 
            s = shapeList[j].sprite;
            s.addEventListener(MouseEvent.MOUSE_DOWN, h_draggable_mouseDown);      
            s.addEventListener(MouseEvent.MOUSE_UP, h_draggable_mouseUp);
            s.useHandCursor = true;
            s.buttonMode = true;
            s.tabEnabled = false;
            item = {obj:args[i],sprite:s};
            handleList.push(item);
          }
        }
       
      }
    }

    
    private function h_draggable_rollOver(evt:Event):void {
      evt.currentTarget.alpha = 0.5;
    }
    
    private function h_draggable_rollOut(evt:Event):void {
      evt.currentTarget.alpha = 1;
    }
    
    
    private function h_draggable_mouseDown(evt:Event):void {
      dragTarget = evt.currentTarget as Sprite;
    }
    
    private function h_draggable_mouseUp(evt:Event):void {
      dragTarget = null;
    }
    
    /*
    * util
    */
    protected function radToDeg(n:Number):Number {
      return n / Math.PI * 180;
    }
    protected function degToRad(n:Number):Number {
      return n * Math.PI / 180;
    }
    protected function rd(n:Number):Number {
      return Math.round(n * 100) / 100;
    }
  }
}

PpObject.as

package {
  import flash.geom.Point;
  public dynamic class PpObject extends Point {
    public function PpObject(x:Number,y:Number):void {
      super(x,y);
    }
  }
}