Xamarin Датчик направления вектора угла - PullRequest
0 голосов
/ 08 февраля 2019

Я использую Xamarin.Essentials.OrientationSensor в своем проекте, и у меня возникают проблемы при интерпретации Quaternion, который API дает мне при новых показаниях.

Описание проблемы

Вот рисунок, описывающиймоя проблема: Orientation vector

Мне нужно определить вектор ориентации v, являющийся нормальным / ортогональным к плоскости телефона (то есть вектор, выходящий из задней части телефона).Затем мне нужно преобразовать этот вектор v в трехмерное пространство состояний, равное (широта, долгота, высота) .Это позволит мне вычислить угол между ориентацией телефона и вектором расстояния d до определенной фиксированной точки F, где d = F - P.Угол может быть получен с помощью скалярного произведения, косинуса и величин v и d.

Что у меня есть

Согласно официальным документам , локальная система координат телефона описывается следующим образом:

Устройство (обычно телефон или планшет) имеет трехмерную систему координат со следующими осями: положительная ось 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 в земную систему координат, которая в соответствии с документами определяется как

Трехмерная система координат Земли имеетследующие оси: положительная ось 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 соответственно.

И тогда мне придется умножить три кватерниона centerQ, qLat и qLon.Тем не менее, я перепробовал все возможные комбинации заказов между тремя, и результаты не имеют никакого смысла.Я знаю, что умножение кватернионов не является коммутативным.

Вот мой код до сих пор

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;
        }
    }
}

Буду признателен за любой намек или мысль по этой проблеме.

...