有没有办法计算两个纬度/经度点之间的角度?
我想要实现的是知道用户的前进方向。例如,用户正在前往北,南,......东南等地
但我只有两点(Lng / Ltd)
THX
答案 0 :(得分:39)
使用this引用来计算角度:
private double angleFromCoordinate(double lat1, double long1, double lat2,
double long2) {
double dLon = (long2 - long1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(dLon);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
brng = (brng + 360) % 360;
brng = 360 - brng; // count degrees counter-clockwise - remove to make clockwise
return brng;
}
答案 1 :(得分:21)
你可以使用谷歌地图computeHeading:
var point1 = new google.maps.LatLng(lat1, lng1);
var point2 = new google.maps.LatLng(lat2, lng2);
var heading = google.maps.geometry.spherical.computeHeading(point1,point2);
答案 2 :(得分:9)
计算两点之间的角度(方位)的通用公式如下:
θ = atan2(sin(Δlong)*cos(lat2), cos(lat1)*sin(lat2) − sin(lat1)*cos(lat2)*cos(Δlong))
请注意,在使用此公式之前,应将角度(θ)转换为弧度 Δlong= long2 - long1。
atan2是几乎所有编程语言中常见的函数(主要在Math包/库中)。通常还有在度和弧度之间进行转换的函数(也在Math包/库中)。
请记住,atan2返回-π... +π范围内的值,要将结果转换为罗盘方位,需要将θ乘以180 /π然后使用(θ+ 360)%360,其中%是模数除法运算返回除法的其余部分。
以下链接是涉及纬度和经度的公式的良好资源。他们还提供其公式的Javascript实现。实际上,这个答案是基于这个页面的信息:
答案 3 :(得分:4)
根据Nayanesh Gupte的回答,如果有人需要,这是一个Python实现:
def angleFromCoordinate(lat1, long1, lat2, long2):
dLon = (long2 - long1)
y = math.sin(dLon) * math.cos(lat2)
x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dLon)
brng = math.atan2(y, x)
brng = math.degrees(brng)
brng = (brng + 360) % 360
brng = 360 - brng # count degrees clockwise - remove to make counter-clockwise
return brng
0度角表示向北的标题。
答案 4 :(得分:3)
在Javascript中,我创建一个函数名称angleFromCoordinate
,在其中我传递了两个lat / lng。此函数将在两个lat / lng
function angleFromCoordinate(lat1,lon1,lat2,lon2) {
var p1 = {
x: lat1,
y: lon1
};
var p2 = {
x: lat2,
y: lon2
};
// angle in radians
var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
// angle in degrees
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
console.log(angleDeg);
return angleDeg;
}
工作代码段
function angleFromCoordinate(lat1,lon1,lat2,lon2) {
var p1 = {
x: lat1,
y: lon1
};
var p2 = {
x: lat2,
y: lon2
};
// angle in radians
var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
// angle in degrees
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
document.getElementById('rotation').innerHTML ="Rotation : "+ angleDeg;
return angleDeg;
}
angleFromCoordinate(37.330604,-122.028947,37.3322109,-122.0329665);
<html>
<p id="rotation">Rotation : </p>
</html>
答案 5 :(得分:3)
如果点之间的距离较小,请使用示例javascript代码 -
brng = Math.atan2(newLat - oldLat, newLong - oldLong);
brng = brng * (180 / Math.PI);
brng = (brng + 360) % 360;
brng = 360 - brng;
答案 6 :(得分:2)
我认为你想要Great Circle bearing的计算。
答案 7 :(得分:2)
如果您使用的是Google Maps(Android),有一种简单的方法-使用SphericalUtil
double angle = SphericalUtil.computeHeading(fromLatLng, toLatLng);
考虑到我们有2点及其经度和纬度 然后创建其Latlng对象
LatLng latlng = new LatLng(latValue, lngValue);
获得2点Latlng后,使用sperical util获取角度
//import com.google.maps.android.SphericalUtil;
double sphericalValue = SphericalUtil.computeHeading(latLng1, latLng2);
SpericalValue是角度。 考虑您有一个汽车图标,并将其相应地转向行驶方向。从latLng1到latLng2然后
Bitmap vehiclePin = rotateIconBitmap(sphericalValue);
mMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(latLng2))
.setIcon(BitmapDescriptorFactory.fromBitmap(vehiclePin));
使用以下方法旋转
Bitmap rotateIconBitmap(double angle) {
Bitmap source = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_vehicle_say_car);
Matrix matrix = new Matrix();
matrix.postRotate((float) angle);
return Bitmap.createBitmap(source, 0, 0,
source.getWidth(), source.getHeight(), matrix, true);
}
轻松实现超级旋转图标的方式
注意:-如果标记图标未指向零度,则可能需要添加90度的偏移量
androidsphereutil是开源的,如果您使用的是Java,请参考它,您可以使用它。
答案 8 :(得分:2)
function calculateAngle(lat, lng) {
var checkLengthInterval = 2;
// Calculate Angle
//If ObjFeed == [] add first object.
if (ObjFeed.length == 0) {
ObjFeed.push({ 'lat': lat, 'lng': lng });
} else {
// Get last object from list to calculate angle betwn last and latest.
var tempNode = ObjFeed[ObjFeed.length - 1];
// If last lat and lng is same as current it will always return 0 angle.so only push lat lng in obj which is diff than last one.
if (!(tempNode.lat == lat && tempNode.lng == lng)) {
ObjFeed.push({ 'lat': lat, 'lng': lng });
} else {
console.log('exact match for lat lng');
}
}
// this is for to keep only few objects in the list and remove other
if (ObjFeed.length >= checkLengthInterval) {
// calculating angle only if previous data point is available
ObjFeed = ObjFeed.slice(-1 * checkLengthInterval); // remove all items in array except last two
var point1 = ObjFeed[ObjFeed.length - checkLengthInterval];
var point2 = ObjFeed[ObjFeed.length - 1];
console.log('previous point1', point1);
console.log('next point2', point2);
var dLng = (point2.lng - point1.lng);
var dLat = (point2.lat - point1.lat);
dLng = dLng * 10000;
dLat = dLat * 10000;
var dlat_by_dlan = 0;
try {
dlat_by_dlan = dLng / dLat;
} catch (err) {
dlat_by_dlan = NaN;
console.log('Exception: dLat == 0');
}
var angleDegreeBearing = 0, angleBearingRad = 0;
angleBearingRad = Math.atan(dlat_by_dlan);
angleDegreeBearing = angleBearingRad * 180 / Math.PI;
if (dLat < 0 && dLng < 0) {
angleDegreeBearing = angleDegreeBearing + 180;
} else if (dLat < 0 && dLng > 0) {
angleDegreeBearing = angleDegreeBearing + 180;
} else if (dLat == 0 && dLng == 0) {
angleDegreeBearing = prevVechicleAngle;
} else if (dlat_by_dlan == NaN) {
angleDegreeBearing = prevVechicleAngle;
}
console.log('angleDegreeBearing', angleDegreeBearing);
} else {
// setting up default angle to 0 if previous data point is not available to calculate actual anglle
console.log('feedArray default angle 0');
angleDegreeBearing = 0;
}
prevVechicleAngle = angleDegreeBearing;
return angleDegreeBearing;
}
答案 9 :(得分:1)
也许这就是你想要的:
cos(say) = (cosd(90-lat(1))) * (cos(90-lat(2)))
+ (sin(90-lat(1))) * (sind(90-lat(2)) * (cosd(abs(Landa(2)-landa(1)))));
答案 10 :(得分:1)
如果您需要精确的旋转椭球方法(即WGS 84),则algorithms会变得很沉重。您可能会受益于GeographicLib,它已经在C / C ++,Java,JavaScript,Python,Matlab / Octave和其他版本中实现。
对于这个问题,在第一点和第二点之间有一个geodesic或rhumb line。
测地线是曲面上两点之间的最短路径。这是“用户前往”位置的最常见解释(来自问题),因为它是最短和最直接的。可以使用GeodSolve来解决反测地线计算问题。您也可以使用online interface。该工具具有输入/输出:
lat1 lon1 lat2 lon2 → azi1 azi2 s12
其中 lat1 lon1 是第一个点的坐标对,而 lat2 lon2 是第二个点的坐标对。所有单位均为度(不是弧度)。结果 azi1 或α 1 是从起点开始的方位角(又称方位角),从北向顺时针方向给出。第二个方位角在第二个点,因为沿着测地线的两个点之间的角度不是恒定的。 s12 是两点之间的距离,以米为单位,精度为15 nm。
一条横线连接两个坐标点,它们具有恒定的方位角(或方位角)。 可以使用RhumbSolve来解决反摆线计算问题。您也可以使用online interface。该工具具有输入/输出:
lat1 lon1 lat2 lon2 → azi12 s12
这些参数与GeodSolve相同,除了 azi12 是两点之间的恒定角度。
答案 11 :(得分:1)
要提供标题,您必须计算方位。
了解方位读数this article。
根据这个article (section bearing),公式为:
θ = atan2( sin Δλ ⋅ cos φ2 , cos φ1 ⋅ sin φ2 − sin φ1 ⋅ cos φ2 ⋅ cos Δλ )
where φ1, λ1 is the start point,
φ2, λ2 the end point,
Δλ is the difference in longitude`
以下是关于如何计算以Lat / Lon表示的两点之间的角度(以度为单位)的示例。 (用C#完成)
让我们说Point
是一个简单的类,有两个double
属性X(经度)和Y(持纬度)。
public double ComputeBearing(Point start,Point end)
{
var φ1 = start.Y; //latitude 1
var λ1 = start.X; //longitude 1
var φ2 = end.Y; //latitude 2
var λ2 = end.X; //longitude 2
var y = Math.Sin(this.degreeToRadian(λ2 - λ1)) * Math.Cos(this.degreeToRadian(φ2));
var x = Math.Cos(this.degreeToRadian(φ1)) * Math.Sin(this.degreeToRadian(φ2)) - Math.Sin(this.degreeToRadian(φ1)) * Math.Cos(this.degreeToRadian(φ2)) * Math.Cos(this.degreeToRadian(λ2 - λ1));
var θ = Math.Atan2(y, x);
θ = this.radianToDegree(θ);
return θ;
}
使用以下方法:
public double degreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
public double radianToDegree(double angle)
{
return angle * (180.0 / Math.PI);
}
通过使用ComputeBearing
,您可以轻松获得以度数表示的角度,可以轻松地用作标题
答案 12 :(得分:1)
如果有人需要PHP
代码来实现此功能:
/**
* Calculate angle between 2 given latLng
* @param float $lat1
* @param float $lat2
* @param float $lng1
* @param float $lng2
* @return integer
*/
function angle($lat1, $lat2, $lng1, $lng2) {
$dLon = $lng2 - $lng1;
$y = sin($dLon) * cos($lat2);
$x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dLon);
return 360 - ((rad2deg(atan2($y, $x)) + 360) % 360);
}
答案 13 :(得分:1)
对于那些使用C / C ++的人,下面是经过测试的代码:
static const auto PI = 3.14159265358979323846, diameterOfEarthMeters = 6371.0 * 2 * 1000;
double degreeToRadian (double degree) { return (degree * PI / 180); };
double radianToDegree (double radian) { return (radian * 180 / PI); };
double CoordinatesToAngle (const double latitude1,
const double longitude1,
const double latitude2,
const double longitude2)
{
const auto longitudeDifferenceRadians = degreeToRadian(longitude2 - longitude1);
auto latitude1Radian = degreeToRadian(latitude1),
latitude2Radian = degreeToRadian(latitude2);
const auto x = std::cos(latitude1Radian) * std::sin(latitude2Radian) -
std::sin(latitude1Radian) * std::cos(latitude2Radian) *
std::cos(longitudeDifferenceRadians);
const auto y = std::sin(longitudeDifferenceRadians) * std::cos(latitude2Radian);
return radianToDegree(std::atan2(y, x));
}
double CoordinatesToMeters (const double latitude1,
const double longitude1,
const double latitude2,
const double longitude2)
{
auto latitude1Radian = degreeToRadian(latitude1),
longitude1Radian = degreeToRadian(longitude1),
latitude2Radian = degreeToRadian(latitude2),
longitude2Radian = degreeToRadian(longitude2);
auto x = std::sin((latitude2Radian - latitude1Radian) / 2),
y = std::sin((longitude2Radian - longitude1Radian) / 2);
return diameterOfEarthMeters *
std::asin(std::sqrt((x * x) +
(std::cos(latitude1Radian) * std::cos(latitude2Radian) * y * y)));
}
答案 14 :(得分:0)
考虑 Nayanesh Gupte 的回答及其评论。我已经更改了部分代码并在$('#addDataset').click(function() {
var background = randomColor(0.5);
var nextCompanyLabel = 6;
var newDataset = {
label: label[nextCompanyLabel++],
borderColor: background,
backgroundColor: background,
pointBorderColor: background,
pointBackgroundColor: background,
pointBorderWidth: 1,
fill: false,
data: [],
};
for (var index = 0; index < config.data.labels.length; ++index) {
newDataset.data.push(randomScalingFactor());
}
config.data.datasets.push(newDataset);
window.myLine.update();
});
中编写了它。
这是功能:
PHP
答案 15 :(得分:0)
确保它的竖线不是一个很大的圆形轴承 初始轴承根据距离变化
double angle= Math.min((pbearingf-tbearingf) < 0 ? pbearingf-tbearingf+360:pbearingf-tbearingf, (tbearingf-pbearingf)<0?tbearingf-pbearingf+360:tbearingf-pbearingf);
答案 16 :(得分:0)
使用javascript,只需使用Turf:
var point1 = turf.point([-75.343, 39.984]);
var point2 = turf.point([-75.534, 39.123]);
var bearing = turf.bearing(point1, point2);