我希望创建一个指南针/箭头,就像我们在 AroundMe Mobile App 中看到的那样,它指向地图上的一个引脚与我的移动位置相对应并在我更新时更新箭头移动电话。
我很难理解如何做到这一点,我找不到任何可以解释它的指南或教程。
我在网上找到的是轴承功能,我围绕它创建了一个指令:
app.directive('arrow', function () {
function bearing(lat1, lng1, lat2, lng2) {
var dLon = (lng2 - lng1);
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
var rad = Math.atan2(y, x);
var brng = toDeg(rad);
return (brng + 360) % 360;
}
function toRad(deg) {
return deg * Math.PI / 180;
}
function toDeg(rad) {
return rad * 180 / Math.PI;
}
return {
restrict: 'E',
link: function (scope, element, attrs) {
var arrowAngle = bearing(scope.user.position.lat, scope.user.position.lng, attrs.lat, attrs.lng);
element.parent().css('transform', 'rotate(' + arrowAngle + 'deg)');
}
};
});
似乎更新箭头方向但不幸的是它不是正确的方向,因为它不是使用移动magneticHeading
位置计算的。
所以我添加了设备方向的ngCordova
插件来获取magneticHeading
,现在我不确切知道如何使用它以及{ {1}}功能。
bearing
我试图在return语句中添加它:
$cordovaDeviceOrientation.getCurrentHeading().then(function(result) {
var magneticHeading = result.magneticHeading;
var arrowAngle = bearing(scope.user.position.lat, scope.user.position.lng, attrs.lat, attrs.lng, magneticHeading);
element.parent().css('transform', 'rotate(' + arrowAngle + 'deg)');
});
或:
return (brng - heading) % 360;
使用观察者实现此代码我看到箭头移动但不在确切的位置...例如,从我的位置和箭头应该指向 N 的指针,它指向电子
始终在线查找我找不到任何教程/问题来查找return (heading - ((brng + 360) % 360));
和lat/lng point
之间的关系。
也许我接近解决方案,但我无法独自前进。
我也试图寻找数学公式,但即使理解和实施它也会有巨大的痛苦。
我希望你能提供帮助。
答案 0 :(得分:1)
很难对这个问题给出明确的答案,因为很大程度上取决于实际的图形表示。例如,您指向rotate(0deg)
的哪个方向。
我可以解释您找到的公式,这可能有助于您自己清除问题。困难的部分如下:
var dLon = (lng2 - lng1);
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
var rad = Math.atan2(y, x);
你在这里看到的是Haversines公式(https://en.wikipedia.org/wiki/Haversine_formula)。通常可以用两组坐标就足够了,并计算它们之间的角度。当使用纬度和经度时,这将不起作用,因为地球不是平坦的表面。前三行是Haversine,结果(x
和y
)是unit circle
(https://en.wikipedia.org/wiki/Unit_circle)
下一步是计算从该单位圆上的点到中心的角度。我们可以使用arctangant
来实现此目的。 Javascript有一个辅助函数atan2
,简化了这个过程。结果很简单,您的点朝向圆心的角度。换句话说,您对您的兴趣点的立场。结果是以弧度为单位,需要转换为度数。 (https://en.wikipedia.org/wiki/Atan2)
带有平面坐标系的简化版本如下所示:
var deltaX = poi.x - you.x;
var deltaY = you.y - poi.y;
var rotation = toDeg(Math.atan2(deltaX, deltaY));
bearingElement.css('transform', 'rotate(' + rotation + 'deg)');
poi
是兴趣点,you
是您的位置。
要补偿自己的旋转,您需要减去自己的旋转。在上面的示例中,结果将变为:
var deltaX = poi.x - you.x;
var deltaY = you.y - poi.y;
var rotation = toDeg(Math.atan2(deltaX, deltaY));
rotation -= you.rotation;
bearingElement.css('transform', 'rotate(' + rotation + 'deg)');
我做了一个Plunckr,你可以看到一个简单的平面坐标系。您可以移动和转动you
和point of interest
。即使您旋转'你','你'内的箭头也会始终指向poi
。这是因为我们补偿了我们自己的轮换。
https://plnkr.co/edit/OJBGWsdcWp3nAkPk4lpC?p=preview
请注意Plunckr中“零”位置始终位于北方。检查您的应用以查看您的“零”位置。相应地调整它,你的脚本就可以了。
希望这会有所帮助: - )