[osflash] drift problem rotating an object around an arbitrary axis

larry kirschner larrykirschner at gmail.com
Wed Feb 14 19:54:30 EST 2007


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>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://osflash.org/pipermail/osflash_osflash.org/attachments/20070214/115ae79c/attachment-0001.htm


More information about the osflash mailing list