Actionscript 3 AS3中陀螺仪全景角计算的数学方法

Actionscript 3 AS3中陀螺仪全景角计算的数学方法,actionscript-3,math,mobile,air,gyroscope,Actionscript 3,Math,Mobile,Air,Gyroscope,我正在尝试添加数学,用陀螺仪控制全景图,并且正在努力。这是AS3内置的移动应用程序 我得到了来自陀螺仪(x和y)的数据,还有当前的角度(平移和倾斜)。我想做的是根据陀螺仪的数据用新角度更新cameraController 我一直在尝试将我在上面找到的Javascript转换为ActionScript3,它可以正常工作,但不是真的 编辑 谢谢,我尝试了这些改变,我添加了相机回滚,因为euler数学需要它,它运行,但数学有问题 全景图似乎只是向上和向左漂移,在以另一种方式移动手机一段时间后,它会向下

我正在尝试添加数学,用陀螺仪控制全景图,并且正在努力。这是AS3内置的移动应用程序

我得到了来自陀螺仪(x和y)的数据,还有当前的角度(平移和倾斜)。我想做的是根据陀螺仪的数据用新角度更新cameraController

我一直在尝试将我在上面找到的Javascript转换为ActionScript3,它可以正常工作,但不是真的

编辑

谢谢,我尝试了这些改变,我添加了相机回滚,因为euler数学需要它,它运行,但数学有问题

全景图似乎只是向上和向左漂移,在以另一种方式移动手机一段时间后,它会向下漂移,然后向右移动

你能看到我在Javascript中遗漏的重要内容吗

import com.adobe.nativeExtensions.GyroscopeEvent;

import flash.events.Event;
import flash.geom.Orientation3D;

public class GyroscopeMaths
{
    public function GyroscopeMaths()
    {
        super();
    }

    private var isTopAccessible:Boolean = false;
    private var isDeviceAvailable:Boolean;
    private var isEnabled:Boolean = false;
    private var vElasticity:Number = 0;
    private var isVRelative:Boolean = false;
    private var isCamRoll:Boolean = false;
    private var friction:Number = 0.5;
    private var isTouching:Boolean = false;
    private var validSample:Boolean = false;
    private var firstSample:* = null;
    private var hOffset:Number = 0;
    private var vOffset:Number = 0;
    private var hLookAt:Number = 0;
    private var vLookAt:Number = 0;
    private var camRoll:Number = 0;
    private var vLookAtNow:Number = 0;
    private var hLookAtNow:Number = 0;
    private var hSpeed:Number = 0;
    private var vSpeed:Number = 0;
    private var vElasticSpeed:Number = 0;
    private var camRollNow:Number;
    private var pitch:Number;
    private var yaw:Number;
    private var altYaw:Number;
    private var factor:Number;
    private var degRad:Number = Math.PI / 180;

    public function handleDeviceOrientation(x:Number, y:Number, z:Number):void {
        // Process event.alpha, event.beta and event.gamma
        var orientation:* = rotateEuler({
            "yaw":y * degRad,
            "pitch":x * degRad,
            "roll": z * degRad
        });
        yaw = wrapAngle(orientation.yaw / degRad);
        pitch = orientation.pitch / degRad;
        altYaw = yaw, factor;
        hLookAtNow = Pano.instance.pan;
        vLookAtNow = Pano.instance.tilt;
        hSpeed = hLookAtNow - hLookAt,
            vSpeed = vLookAtNow - vLookAt;

        // Ignore all sample until we get a sample that is different from the first sample
        if (!validSample) {
            if (firstSample == null) {
                firstSample = orientation;
            } else {
                if (orientation.yaw != firstSample.yaw || orientation.pitch != firstSample.pitch || orientation.roll != firstSample.roll) {
                    firstSample = null;
                    validSample = true;
                    if (isVRelative) {
                        vOffset = -pitch;
                    }
                }
            }
            return;
        }

        // Fix gimbal lock
        if (Math.abs(pitch) > 70) {
            altYaw = y;


            var altYaw:Number = wrapAngle(altYaw);
            if (Math.abs(altYaw - yaw) > 180) {
                altYaw += (altYaw < yaw) ? 360 :-360;
            }

            var factor:Number = Math.min(1, (Math.abs(pitch) - 70) / 10);
            yaw = yaw * (1 - factor) + altYaw * factor;

            //camRoll *= (1 - factor);
        }

        // Track view change since last orientation event
        // ie:user has manually panned, or krpano has altered lookat
        hOffset += hSpeed;
        vOffset += vSpeed;

        // Clamp vOffset
        if (Math.abs(pitch + vOffset) > 90) {
            vOffset = (pitch + vOffset > 0) ? (90 - pitch) :(-90 - pitch)
        }

        hLookAt = wrapAngle(-yaw - 180 + hOffset);
        vLookAt = Math.max(Math.min((pitch + vOffset), 90), -90);

        // Dampen lookat
        if (Math.abs(hLookAt - hLookAtNow) > 180) {
            hLookAtNow += (hLookAt > hLookAtNow) ? 360 :-360;
        }

        hLookAt = (1 - friction) * hLookAt + friction * hLookAtNow;
        vLookAt = (1 - friction) * vLookAt + friction * vLookAtNow;

        if (Math.abs(camRoll - camRollNow) > 180) {
            camRollNow += (camRoll > camRollNow) ? 360 :-360;
        }

        camRoll = (1 - friction) * camRoll + friction * camRollNow;

        var wAh:Number = wrapAngle(hLookAt);
        Pano.instance.panoGyroChange(wAh, vLookAt);
        //krpano.view.camroll = wrapAngle(camRoll);

        if (vOffset != 0 && vElasticity > 0) {
            if (vSpeed == 0) {
                if (vElasticity == 1) {
                    vOffset = 0;
                    vElasticSpeed = 0;
                } else {
                    //  vElasticSpeed = 1 - ((1 - vElasticSpeed) * krpano.control.touchfriction);
                    vOffset *= 1 - (Math.pow(vElasticity, 2) * vElasticSpeed); // use Math.pow to be able to use saner values

                    if (Math.abs(vOffset) < 0.1) {
                        vOffset = 0;
                        vElasticSpeed = 0;
                    }
                }
            } else {
                vElasticSpeed = 0;
            }
        }
    }

    private function rotateEuler(euler:Object):Object {
        // This function is based on http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
        // and http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm
        trace(euler);
        var heading:Number;
        var bank:Number;
        var attitude:Number;
        var ch:Number = Math.cos(euler.yaw);
        var sh:Number = Math.sin(euler.yaw);
        var ca:Number = Math.cos(euler.pitch);
        var sa:Number = Math.sin(euler.pitch);
        var cb:Number = Math.cos(euler.roll);
        var sb:Number = Math.sin(euler.roll);

        var matrix:Array = [
            sh * sb - ch * sa * cb, -ch * ca, ch * sa * sb + sh * cb,
            ca * cb, -sa, -ca * sb,
            sh * sa * cb + ch * sb, sh * ca, -sh * sa * sb + ch * cb
        ]; // Note:Includes 90 degree rotation around z axis

        /* [m00 m01 m02] 0 1 2
        * [m10 m11 m12] 3 4 5
        * [m20 m21 m22] 6 7 8 */

        if (matrix[3] > 0.9999) {
            // Deal with singularity at north pole
            heading = Math.atan2(matrix[2], matrix[8]);
            attitude = Math.PI / 2;
            bank = 0;
        } else if (matrix[3] < -0.9999) {
            // Deal with singularity at south pole
            heading = Math.atan2(matrix[2], matrix[8]);
            attitude = -Math.PI / 2;
            bank = 0;
        } else {
            heading = Math.atan2(-matrix[6], matrix[0]);
            bank = Math.atan2(-matrix[5], matrix[4]);
            attitude = Math.asin(matrix[3]);
        }

        return {
            yaw:heading,
            pitch:attitude,
            roll:bank
        };
    }

    private function wrapAngle(value:Number):Number {
        value = value % 360;
        return (value <= 180) ? value :value - 360;
    } // wrap a value between -180 and 180
    //function stringToBoolean(value:Number):String 
    //{ return (String("yesontrue1").indexOf( String(value:Number) ) >= 0) };
}
import com.adobe.nativeExtensions.com事件;
导入flash.events.Event;
导入flash.geom.Orientation3D;
公共数学课
{
公共函数(数学)
{
超级();
}
私有变量isTopAccessible:Boolean=false;
私有变量isDeviceAvailable:布尔值;
私有变量isEnabled:Boolean=false;
私有变量的波动率:数值=0;
私有变量isvrrelative:Boolean=false;
私有变量isCamRoll:Boolean=false;
私有var摩擦:数值=0.5;
private-var-isTouching:Boolean=false;
私有变量validSample:Boolean=false;
private var firstSample:*=null;
私有var hOffset:Number=0;
私有变量vOffset:Number=0;
私有变量hLookAt:Number=0;
私有变量vLookAt:Number=0;
私有变量camRoll:编号=0;
私有变量vLookAtNow:Number=0;
私有变量hLookAtNow:Number=0;
私有变量hSpeed:Number=0;
私有变量vSpeed:Number=0;
私有变量velasticpeed:Number=0;
私有变量camRollNow:编号;
专用变桨距:数字;
私有变量:编号;
私有变量:编号;
私有var因子:数量;
私有var DEGRADD:Number=Math.PI/180;
公共函数handleDeviceOrientation(x:编号,y:编号,z:编号):无效{
//处理event.alpha、event.beta和event.gamma
变量方向:*=rotateEuler({
“偏航”:y*降级,
“音高”:x*degRad,
“滚动”:z*D
});
偏航=缠绕(方向偏航/下降);
节距=方向。节距/降级;
altYaw=偏航,系数;
hLookAtNow=Pano.instance.pan;
vLookAtNow=Pano.instance.tilt;
hSpeed=hLookAtNow-hLookAt,
vSpeed=vLookAtNow-vLookAt;
//忽略所有样本,直到得到与第一个样本不同的样本
如果(!validSample){
if(firstSample==null){
第一个样本=方向;
}否则{
if(orientation.yaw!=firstSample.yaw | | orientation.pitch!=firstSample.pitch | | orientation.roll!=firstSample.roll){
firstSample=null;
validSample=true;
如果(是相对的){
vOffset=-音高;
}
}
}
返回;
}
//固定万向节锁
如果(数学绝对值(节距)>70){
altYaw=y;
var-altYaw:Number=wrapAngle(altYaw);
如果(数学abs(高度偏航-偏航)>180){
高度偏航+=(高度偏航<偏航)?360:-360;
}
变量系数:数值=数学最小值(1,(数学绝对值(节距)-70)/10);
偏航=偏航*(1-系数)+偏航*系数;
//凸轮轴*=(1-系数);
}
//自上次定向事件以来的轨迹视图更改
//ie:用户已经手动平移,或者krpano已经改变了注视
hOffset+=hSpeed;
vOffset+=vSpeed;
//夹伏偏移
如果(数学绝对值(节距+偏移量)>90){
音量偏移=(音高+音量偏移>0)?(90音高):(-90音高)
}
hLookAt=绞盘(-偏航-180+hOffset);
vLookAt=数学最大值(数学最小值((螺距+偏移量),90),-90);
//抑制注视
if(Math.abs(hLookAt-hLookAtNow)>180){
hLookAtNow+=(hLookAt>hLookAtNow)?360:-360;
}
hLookAt=(1-摩擦力)*hLookAt+摩擦力*hLookAtNow;
vLookAt=(1-摩擦力)*vLookAt+摩擦力*vLookAtNow;
如果(数学abs(camRoll-camRollNow)>180){
camRollNow+=(camRoll>camRollNow)?360:-360;
}
camRoll=(1-摩擦力)*camRoll+摩擦力*camRollNow;
var wAh:Number=wrapAngle(hLookAt);
Pano.instance.PanoGyrogorChange(哇,vLookAt);
//krpano.view.camroll=wrapAngle(camroll);
如果(vOffset!=0&&vElasticity>0){
如果(vSpeed==0){
如果(vElasticity==1){
vOffset=0;
vElasticSpeed=0;
}否则{
//vElasticSpeed=1-((1-vElasticSpeed)*krpano.control.touchfriction);
vOffset*=1-(Math.pow(vElasticity,2)*vElasticSpeed);//使用Math.pow可以使用更合理的值
if(数学绝对值(偏移量)<0.1){
vOffset=0;
vElasticSpeed=0;
}
}
}否则{
vElasticSpeed=0;
}
}
}
专用函数旋转规则(euler:对象):对象{
//此函数基于http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
//及http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm
轨迹(欧拉);
var标题:编号;
var银行:编号;
var态度:数量;
变量ch:Number=Math.cos(欧拉偏航);
var sh:Number=Math.sin(euler.yaw);
private var isTopAccessible:Boolean = false;
private var isDeviceAvailable:Boolean;
private var isEnabled:Boolean = false;
private var vElasticity:Number = 0;
private var isVRelative:Boolean = false;
private var isCamRoll:Boolean = false;
private var friction:Number = 0.5;
private var isTouching:Boolean = false;
private var validSample:Boolean = false;
private var firstSample:* = null;
private var hOffset:Number = 0;
private var vOffset:Number = 0;
private var hLookAt:Number = 0;
private var vLookAt:Number = 0;
private var camRoll:Number = 0;
private var vLookAtNow:Number = 0;
private var hLookAtNow:Number = 0;
private var hSpeed:Number = 0;
private var vSpeed:Number = 0;
private var vElasticSpeed:Number = 0;
private var camRollNow:Number;
private var pitch:Number;
private var yaw:Number;
private var altYaw:Number;
private var factor:Number;
private var degRad:Number = Math.PI / 180;

public function handleDeviceOrientation(x:Number, y:Number):void {
    // Process event.alpha, event.beta and event.gamma
    var orientation:* = rotateEuler({
        "yaw":y * degRad,
        "pitch":x * degRad,
        "roll":0
    });
    yaw = wrapAngle(orientation.yaw / degRad);
    pitch = orientation.pitch / degRad;
    altYaw = yaw, factor;
    hLookAtNow = Pano.instance.pan;
    vLookAtNow = Pano.instance.tilt;
    hSpeed = hLookAtNow - hLookAt,
    vSpeed = vLookAtNow - vLookAt;

    // Ignore all sample until we get a sample that is different from the first sample
    if (!validSample) {
        if (firstSample == null) {
            firstSample = orientation;
        } else {
            if (orientation.yaw != firstSample.yaw || orientation.pitch != firstSample.pitch || orientation.roll != firstSample.roll) {
                firstSample = null;
                validSample = true;
                if (isVRelative) {
                    vOffset = -pitch;
                }
            }
        }
        return;
    }

    // Fix gimbal lock
    if (Math.abs(pitch) > 70) {
        altYaw = y;

        /*switch(deviceOrientation) {
            case 0:
                if ( pitch>0 )
                altYaw += 180;
                break;
            case 90:
                altYaw += 90;
                break;
            case -90:
                altYaw += -90;
                break;
            case 180:
                if ( pitch<0 )
                altYaw += 180;
                break;
        }*/

        var altYaw:Number = wrapAngle(altYaw);
        if (Math.abs(altYaw - yaw) > 180) {
            altYaw += (altYaw < yaw) ? 360 :-360;
        }

        var factor:Number = Math.min(1, (Math.abs(pitch) - 70) / 10);
        yaw = yaw * (1 - factor) + altYaw * factor;

        //camRoll *= (1 - factor);
    }

    // Track view change since last orientation event
    // ie:user has manually panned, or krpano has altered lookat
    hOffset += hSpeed;
    vOffset += vSpeed;

    // Clamp vOffset
    if (Math.abs(pitch + vOffset) > 90) {
        vOffset = (pitch + vOffset > 0) ? (90 - pitch) :(-90 - pitch)
    }

    hLookAt = wrapAngle(-yaw - 180 + hOffset);
    vLookAt = Math.max(Math.min((pitch + vOffset), 90), -90);

    // Dampen lookat
    if (Math.abs(hLookAt - hLookAtNow) > 180) {
        hLookAtNow += (hLookAt > hLookAtNow) ? 360 :-360;
    }

    hLookAt = (1 - friction) * hLookAt + friction * hLookAtNow;
    vLookAt = (1 - friction) * vLookAt + friction * vLookAtNow;

    if (Math.abs(camRoll - camRollNow) > 180) {
        camRollNow += (camRoll > camRollNow) ? 360 :-360;
    }

    camRoll = (1 - friction) * camRoll + friction * camRollNow;

    var wAh:Number = wrapAngle(hLookAt);
    Pano.instance.panoGyroChange(wAh, vLookAt);
    //krpano.view.camroll = wrapAngle(camRoll);

    if (vOffset != 0 && vElasticity > 0) {
        if (vSpeed == 0) {
            if (vElasticity == 1) {
                vOffset = 0;
                vElasticSpeed = 0;
            } else {
                //  vElasticSpeed = 1 - ((1 - vElasticSpeed) * krpano.control.touchfriction);
                vOffset *= 1 - (Math.pow(vElasticity, 2) * vElasticSpeed); // use Math.pow to be able to use saner values

                if (Math.abs(vOffset) < 0.1) {
                    vOffset = 0;
                    vElasticSpeed = 0;
                }
            }
        } else {
            vElasticSpeed = 0;
        }
    }
}

private function rotateEuler(euler:Object):Object {
    // This function is based on http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
    // and http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm
    trace(euler);
    var heading:Number;
    var bank:Number;
    var attitude:Number;
    var ch:Number = Math.cos(euler.yaw);
    var sh:Number = Math.sin(euler.yaw);
    var ca:Number = Math.cos(euler.pitch);
    var sa:Number = Math.sin(euler.pitch);
    var cb:Number = Math.cos(euler.roll);
    var sb:Number = Math.sin(euler.roll);

    var matrix:Array = [
        sh * sb - ch * sa * cb, -ch * ca, ch * sa * sb + sh * cb,
        ca * cb, -sa, -ca * sb,
        sh * sa * cb + ch * sb, sh * ca, -sh * sa * sb + ch * cb
    ]; // Note:Includes 90 degree rotation around z axis

    /* [m00 m01 m02] 0 1 2
     * [m10 m11 m12] 3 4 5
     * [m20 m21 m22] 6 7 8 */

    if (matrix[3] > 0.9999) {
        // Deal with singularity at north pole
        heading = Math.atan2(matrix[2], matrix[8]);
        attitude = Math.PI / 2;
        bank = 0;
    } else if (matrix[3] < -0.9999) {
        // Deal with singularity at south pole
        heading = Math.atan2(matrix[2], matrix[8]);
        attitude = -Math.PI / 2;
        bank = 0;
    } else {
        heading = Math.atan2(-matrix[6], matrix[0]);
        bank = Math.atan2(-matrix[5], matrix[4]);
        attitude = Math.asin(matrix[3]);
    }

    return {
        yaw:heading,
        pitch:attitude,
        roll:bank
    };
}

private function wrapAngle(value:Number):Number {
    value = value % 360;
    return (value <= 180) ? value :value - 360;
} // wrap a value between -180 and 180
//function stringToBoolean(value:Number):String 
//{ return (String("yesontrue1").indexOf( String(value:Number) ) >= 0) };