我Xamarin.Essentials.OrientationSensor
在我的项目中使用,我无法解释Quaternion
API 给我的新读数。
问题描述
我需要确定一个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 轴旋转。
然后我将不得不乘以三个四元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;
}
}
}
我将不胜感激有关此问题的任何提示或想法。