Hello,

I need a way to programmatically rotate an object around an arbitrary axis.

I've been trying to implement this using the objects transform matrix, with
the basic algorithm:

1) Translate axis point to origin
2) Rotate
3) Translate back to axis point

This approach seems to work, except that on each rotation the object
slightly off the axis.

OBSERVATIONS:

1) The object always seems to drift in the -x/-y direction, even if I
reverse the direction of rotation
2) On each rotation in order to translate the axis point back to the origin,
I need to calculate the location of the axis point given the rotating
object's current rotation. I notice that after the first rotation, the
distance from the rotating object's registration point to its access is
always slightly off. I've tried calculating the axis position using
Matrix::deltaTransformPoint() and Point::polar() and I have the same drift
problem with both.

ENVIRONMENT: Flash 9/Flex 2

Anyone have any ideas what's going on here or how to fix this?

Big thanks in advance for any help.

--Larry

CODE SAMPLE:

I made this stripped down example of the problem in Flex:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
   xmlns:mx="http://www.adobe.com/2006/mxml";
   layout="absolute"
   creationComplete="init();">

   <mx:Script>
       <![CDATA[

           private var m_object:Sprite = null;
           private var m_axis:Sprite = null;
           private var m_axisFromObjOrig:Point = null;

           private static var OBJECT_X:Number = 100;
           private static var OBJECT_Y:Number = 100;

           private static var OBJECT_WIDTH:Number = 100;
           private static var OBJECT_HEIGHT:Number = 40;

           private static var AXIS_X_OFF:Number = OBJECT_WIDTH/2;
           private static var AXIS_Y_OFF:Number = 0;

           public function init():void
           {
               var stage:Stage = Application.application.parent.stage;

               /*====================================
                * DRAW THE MAIN OBJECT
                *===================================*/
               m_object = new Sprite();

               stage.addChild(m_object);
               m_object.x = OBJECT_X;
               m_object.y = OBJECT_Y;

               var g:Graphics = m_object.graphics;
               g.lineStyle(1, 0xff0000);
               g.beginFill(0x00ff00);
               g.drawEllipse(0 - (OBJECT_WIDTH/2), 0 - (OBJECT_HEIGHT/2),
OBJECT_WIDTH, OBJECT_HEIGHT);
               g.endFill();

               /*=============================================
                * DRAW THE CENTERPOINT INSIDE THE MAIN OBJECT
                *============================================*/
               var centerPoint:Sprite = new Sprite();
               m_object.addChild(centerPoint);
               centerPoint.x = 0;
               centerPoint.y = 0;

               g = centerPoint.graphics;
               g.lineStyle(1, 0x000000);
               g.beginFill(0x000000);
               g.drawCircle(0, 0, .5);
               g.endFill();

               /*=============================================
                * DRAW THE AXIS POINT INSIDE THE MAIN OBJECT
                *============================================*/
               var axisPoint:Sprite = new Sprite();
               m_object.addChild(axisPoint);
               axisPoint.x = AXIS_X_OFF;
               axisPoint.y = AXIS_Y_OFF;

               g = centerPoint.graphics;
               g.lineStyle(1, 0x000000);
               g.beginFill(0x000000);
               g.drawCircle(AXIS_X_OFF, AXIS_Y_OFF, 1);
               g.endFill();


               /*=============================================
                * DRAW THE AXIS POINT FIXED ON THE STAGE
                *============================================*/
               m_axis = new Sprite();

               stage.addChild(m_axis);

               m_axis.x = OBJECT_X + AXIS_X_OFF;
               m_axis.y = OBJECT_Y + AXIS_Y_OFF;

               g = m_axis.graphics;
               g.lineStyle(1, 0x000000);
               g.beginFill(0x000000);
               g.drawCircle(0, 0, 2);
               g.endFill();

               m_axisFromObjOrig = new Point(OBJECT_WIDTH/2, 0);

               var t:Timer = new Timer(20, 1000);


               /*====================================================
                * BELOW YOU CAN SWAP THE COMMENTS TO USE EITHER
                * THE rotateWithDeltaTransform
                * OR THE rotateWithPolar
                * VERSION OF THE ROTATION FUNCTION
                *===================================================*/

               //t.addEventListener(TimerEvent.TIMER,
rotateWithDeltaTransform);
               t.addEventListener(TimerEvent.TIMER, rotateWithPolar);

               t.start();
           }

           public function rotateWithDeltaTransform(evt:Event = null,
angle:Number = Math.PI/360):void
           {
               var axis:Point =
m_object.transform.matrix.deltaTransformPoint(m_axisFromObjOrig);

               axisRotate(m_object, axis, angle);
           }

           public function rotateWithPolar(evt:Event = null, angle:Number =
Math.PI/360):void
           {
               var rotRads:Number = Math.PI * m_object.rotation / 180;
               var axis:Point = Point.polar(OBJECT_WIDTH/2, rotRads);

               axisRotate(m_object, axis, angle);
           }

           private function axisRotate(obj:DisplayObject, axis:Point,
angle:Number):void
           {
               validateAxisLen(axis);

               var temp:Matrix = obj.transform.matrix;

               var pivotX:Number = obj.x + axis.x;
               var pivotY:Number = obj.y + axis.y;

               temp.translate(0 - pivotX, 0 - pivotY);

               temp.rotate(angle);

               temp.translate(pivotX, pivotY);

               obj.transform.matrix = temp;
           }

           private function validateAxisLen(axis:Point):void
           {
               var orig:Point = new Point(0, 0);
               var len:Number = Point.distance(orig, axis);
               var correctLen:Number = Point.distance(orig,
m_axisFromObjOrig);

               var err:Number = correctLen - len;
               if(err != 0) {
                   trace("Axis location is off by " + err + ": len="
                       + len + ", correctLen=" + correctLen);
               }
           }
       ]]>
   </mx:Script>
</mx:Application>
_______________________________________________
osflash mailing list
[email protected]
http://osflash.org/mailman/listinfo/osflash_osflash.org

Reply via email to