3

Xamarin.Essentials.OrientationSensor在我的项目中使用,我无法解释QuaternionAPI 给我的新读数。

问题描述

这是描述我的问题的图: 方向向量

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

到目前为止我所拥有的

根据官方文档,手机的本地坐标系描述如下:

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

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

这个问题中,我已经了解到,给定的四元数是相对的,我需要一个参考四元数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+高度,这就是它变得棘手的地方。

我尝试定义两个额外的四元数,用于从地球坐标系(如文档中所述)到 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;
        }
    }
}

我将不胜感激有关此问题的任何提示或想法。

4

0 回答 0