我在项目中使用Xamarin.Essentials.OrientationSensor
,但在解释Quaternion
API给我的新读物时遇到了麻烦。
我需要确定与手机平面垂直/正交的方向向量v
(即从手机背面出来的向量)。然后,我需要将此向量v
变换到(纬度,经度,海拔)的3D状态空间中。这将使我能够计算手机的方向与到特定固定点d
的距离矢量F
之间的角度,其中d = F - P
。然后可以通过使用点积,余弦和v
和d
的大小来获得角度。
根据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轴。
然后我必须将三个四元数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;
}
}
}
对于这个问题的任何提示或思考,我将不胜感激。