Xamarin方向传感器矢量角

时间:2019-02-08 09:29:13

标签: c# xamarin xamarin.forms navigation xamarin.essentials

我在项目中使用Xamarin.Essentials.OrientationSensor,但在解释Quaternion API给我的新读物时遇到了麻烦。

问题描述

以下是描述我的问题的数字: Orientation vector

我需要确定与手机平面垂直/正交的方向向量v(即从手机背面出来的向量)。然后,我需要将此向量v 变换(纬度,经度,海拔)的3D状态空间中。这将使我能够计算手机的方向与到特定固定点d的距离矢量F之间的角度,其中d = F - P。然后可以通过使用点积,余弦和vd的大小来获得角度。

我到目前为止所拥有的

根据official docs,电话的本地坐标系描述如下:

  

设备(通常是手机或平板电脑)具有3D坐标系   带有以下轴:正X轴指向的右侧。   以纵向模式显示。 Y轴正点指向   设备处于纵向模式。 Z轴正点指向   屏幕。

这意味着我正在寻找的向量v在手机的本地坐标系中为 v =(0,0,-1)

this question中,我已经知道,给定的四元数是相对的,我需要一个参考四元数centerQ进行转换:

void onNewOrientation(Quaternion q)
{
    if (centerQ == Quaternion.Identity)
    {
        centerQ = Quaternion.Inverse(q);
        return;
    }
}

然后我可以使用Quaternion.Transform(v, centerQ)v转换为地球的坐标系,根据文档将其定义为

  

地球的3D坐标系具有以下轴:   正X轴与地球表面和点相切   东。 Y轴的正方向也与地球表面相切   并指向北。正Z轴垂直于表面   并指向地球。

但是,我需要将v转换为WGS + altitude,这很棘手。

我尝试定义两个附加的四元数,用于从地球坐标系(如文档所述)到WGS的转换,如下所示:

var phi = -1 * lastloc.Latitude * Util.DEGTORAD;
var lam = lastloc.Longitude * Util.DEGTORAD;

var qLat = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), (float)phi);
var qLon = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), (float)lam);

因为纬度基本上是分别绕x轴旋转和经度分别围绕y轴。

然后我必须将三个四元数centerQqLatqLon相乘。但是,我尝试了三个之间所有可能的顺序组合,结果都没有任何意义。我知道四元数乘法不是可交换的。

到目前为止,这是我的代码

namespace Foo.ViewModels
{
    public class DebugViewModel : BaseViewModel
    {
        private Quaternion centerQ;
        private static Vector3 vec3out = new Vector3(0f, 0f, -1f);
        private static Location fixPos;
        private Location lastloc;

        public DebugViewModel()
        {
            centerQ = Quaternion.Identity;
            lastloc = null;

            fixPos = new Location()
            {
                Latitude = 0,  // anonymized
                Longitude = 0, // anonymized
                Altitude = 0   // anonymized
            };

            // Create reactive observable
            Observable.FromEventPattern<OrientationSensorChangedEventArgs>(
                    ev => OrientationSensor.ReadingChanged += ev,
                    ev => OrientationSensor.ReadingChanged -= ev)
                .Select(eventPattern => eventPattern.EventArgs.Reading.Orientation)
                //.Throttle(TimeSpan.FromMilliseconds(20))
                .Subscribe(this.onNewOrientation);

            OrientationSensor.Start(SensorSpeed.UI);
        }

        void onNewOrientation(Quaternion q)
        {
            if (centerQ == Quaternion.Identity)
            {
                centerQ = Quaternion.Inverse(q);
                return;
            }

            if (lastloc == null)
            {
                return;
            }

            var qi = Quaternion.Inverse(q);
            var qq = Quaternion.Multiply(centerQ, q);

            // get local quaternion
            var phi = -1 * lastloc.Latitude * Util.DEGTORAD;
            var lam = lastloc.Longitude * Util.DEGTORAD;

            var qLat = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), (float)phi);
            var qLon = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), (float)lam);
            var qLati = Quaternion.Inverse(qLat);
            var qLoni = Quaternion.Inverse(qLon);

            var q1 = Quaternion.Multiply(qLat, qLon);
            var q2 = Quaternion.Multiply(q1, qq);

            Vector3 aa = Vector3.Transform(vec3out, q2);

            Vector3 myP = new Vector3(
                (float)lastloc.Latitude, 
                (float)lastloc.Longitude, 
                (float)lastloc.Altitude);

            Vector3 drP = new Vector3(
                (float)twrPos.Latitude,
                (float)twrPos.Longitude,
                (float)twrPos.Altitude);

            Vector3 d = Vector3.Normalize(drP - myP);

            float alpha = Util.vecAngle(d, aa) * (float)Util.RADTODEG;
        }
    }
}

对于这个问题的任何提示或思考,我将不胜感激。

0 个答案:

没有答案