计算新的经度,从旧的纬度 + n 米

我想创建2个新的经度和2个新的纬度的基础上坐标和米的距离,我想创建一个很好的边界框周围的某一点。它是一个城市的一部分和最大 ± 1500米。因此,我不认为地球的曲率必须被考虑在内。

我有 50.0452345(x)和 4.3242234(y) ,我想知道 x + 500米,x-500米,y-500米,y + 500米

我找到了许多算法,但几乎都是处理点之间的距离。

120476 次浏览

你检查过 我如何找到 lat/long,这是 x 公里以北的一个给定 lat/long吗?

这些计算最多只能算是烦人的,我已经做过很多次了。半正矢公式会成为你的朋友。

参考资料: http://www.movable-type.co.uk/scripts/latlong.html

每度经度的公里数大约是

(pi/180) * r_earth * cos(theta*pi/180)

其中 theta是纬度(度) ,r_earth是大约6378公里。

在所有地点,每纬度的公里数大致相同

(pi/180) * r_earth = 111 km / degree

所以你可以这样做:

new_latitude  = latitude  + (dy / r_earth) * (180 / pi);
new_longitude = longitude + (dx / r_earth) * (180 / pi) / cos(latitude * pi/180);

只要 dxdy与地球半径相比较小,你就不会太接近两极。

这个被接受的答案是完全正确的,而且很有效。我做了一些调整,变成了这样:

double meters = 50;


// number of km per degree = ~111km (111.32 in google maps, but range varies
between 110.567km at the equator and 111.699km at the poles)
double coef = meters / 111.32;


double new_lat = my_lat + coef;


// pi / 180 ~= 0.01745
double new_long = my_long + coef / Math.cos(my_lat * 0.01745);

希望这个也有用。

纬度:

var earth = 6378.137,  //radius of the earth in kilometer
pi = Math.PI,
m = (1 / ((2 * pi / 360) * earth)) / 1000;  //1 meter in degree


var new_latitude = latitude + (your_meters * m);

对于经度来说:

var earth = 6378.137,  //radius of the earth in kilometer
pi = Math.PI,
cos = Math.cos,
m = (1 / ((2 * pi / 360) * earth)) / 1000;  //1 meter in degree


var new_longitude = longitude + (your_meters * m) / cos(latitude * (pi / 180));

变量 your_meters可以包含正值或负值。

var meters = 50;
var coef = meters * 0.0000089;
var new_lat = map.getCenter().lat.apply() + coef;
var new_long = map.getCenter().lng.apply() + coef / Math.cos(new_lat * 0.018);
map.setCenter({lat:new_lat, lng:new_long});

我花了大约两个小时通过@nibot 算出了解决方案,我只需要一个方法来创建一个边界框,给出它的中心点和宽度/高度(或半径)公里:

我在数学上和地理上都不完全理解这个解。 我调整了解决方案(通过尝试和错误)以得到四个坐标。以公里为单位的距离,根据目前的位置和距离,我们转移到四个坐标中的新位置:

北区:

private static Position ToNorthPosition(Position center, double northDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_latitude = center.Lat + (northDistance / r_earth) * (180 / pi);
return new Position(new_latitude, center.Long);
}

东区:

private static Position ToEastPosition(Position center, double eastDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_longitude = center.Long + (eastDistance / r_earth) * (180 / pi) / Math.Cos(center.Lat * pi / 180);
return new Position(center.Lat, new_longitude);
}

南区:

private static Position ToSouthPosition(Position center, double southDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_latitude = center.Lat - (southDistance / r_earth) * (180 / pi);
return new Position(new_latitude, center.Long);
}

西:

private static Position ToWestPosition(Position center, double westDistance)
{
double r_earth = 6378;
var pi = Math.PI;
var new_longitude = center.Long - (westDistance / r_earth) * (180 / pi) / Math.Cos(center.Lat * pi / 180);
return new Position(center.Lat, new_longitude);
}

如果你不需要非常精确的话,那么每10000米对于经纬度来说就是0.1米。 例如,我想从我的数据库中加载点 A 周围3000米的位置:

double newMeter =  3000 * 0.1 / 10000;
double lat1 = point_A.latitude - newMeter;
double lat2 = point_A.latitude + newMeter;
double lon1 = point_A.longitude - newMeter;
double lon1 = point_A.longitude + newMeter;
Cursor c = mDb.rawQuery("select * from TABLE1  where lat >= " + lat1 + " and lat <= " + lat2 + " and lon >= " + lon1 + " and lon <= " + lon2 + " order by id", null);
public double MeterToDegree(double meters, double latitude)
{
return meters / (111.32 * 1000 * Math.Cos(latitude * (Math.PI / 180)));
}

看看官方谷歌地图文档(链接在下面) ,因为他们在简单的地图上解决了国家间距离的问题:)

我推荐使用这个解决方案来简单/简单地解决有边界的问题,这样您就可以知道您正在用边界解决问题的哪个区域(不推荐使用全局)

注:

纬度线是东西向的,标记了一个点的南北位置。纬度线称为平行线,总共有180度的纬度。每个纬度之间的距离约为69英里(110公里)。

经度之间的距离缩小了离赤道的距离。赤道经度之间的距离与纬度相同,大约是69英里(110公里)。在北纬45度或南纬45度,两者之间的距离约为49英里(79公里)。经度之间的距离达到零的极点,因为子午线收敛在这一点。

原始来源1 原始来源2 enter image description here

谷歌地图官方文档: 代码示例: 自动完成限制到多个国家

请看他们代码中关于如何用距离中心 + 10公里乘以 +/-0.1度解决问题的部分

function initMap(): void {
const map = new google.maps.Map(
document.getElementById("map") as HTMLElement,
{
center: { lat: 50.064192, lng: -130.605469 },
zoom: 3,
}
);
const card = document.getElementById("pac-card") as HTMLElement;
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(card);
const center = { lat: 50.064192, lng: -130.605469 };


// Create a bounding box with sides ~10km away from the center point
const defaultBounds = {
north: center.lat + 0.1,
south: center.lat - 0.1,
east: center.lng + 0.1,
west: center.lng - 0.1,
};


const input = document.getElementById("pac-input") as HTMLInputElement;
const options = {
bounds: defaultBounds,
componentRestrictions: { country: "us" },
fields: ["address_components", "geometry", "icon", "name"],
origin: center,
strictBounds: false,
types: ["establishment"],
};

这就是我在 VBA 中所做的,似乎对我有用。计算是用英尺而不是米

Public Function CalcLong(OrigLong As Double, OrigLat As Double, DirLong As String, DirLat As String, DistLong As Double, DistLat As Double)
Dim FT As Double
Dim NewLong, NewLat As Double
FT = 1 / ((2 * WorksheetFunction.Pi / 360) * 20902230.971129)
    

If DirLong = "W" Then
NewLat = CalcLat(OrigLong, OrigLat, DirLong, DirLat, DistLong, DistLat)
NewLong = OrigLong - ((FT * DistLong) / Cos(NewLat * (WorksheetFunction.Pi / 180)))
CalcLong = NewLong
Else
NewLong = OrigLong + ((FT * DistLong) / Math.Cos(CalcLat(OrigLong, OrigLat, DirLong, DirLat, DistLong, DistLat) * (WorksheetFunction.Pi / 180)))
CalcLong = NewLong
End If
    

End Function




Public Function CalcLat(OrigLong As Double, OrigLat As Double, DirLong As String, DirLat As String, DistLong As Double, DistLat As Double) As Double
Dim FT As Double
Dim NewLat As Double
    

FT = 1 / ((2 * WorksheetFunction.Pi / 360) * 20902230.971129)
    

If DirLat = "S" Then
NewLat = (OrigLat - (FT * DistLat))
CalcLat = NewLat
Else
NewLat = (OrigLat + (FT * DistLat))
CalcLat = NewLat
End If
    

End Function


运行 Python 代码以偏移坐标10米。

def add_blur(lat, long):
meters = 10
blur_factor = meters * 0.000006279
new_lat = lat + blur_factor
new_long = long + blur_factor / math.cos(lat * 0.018)
return new_lat, new_long

公布此方法以保证完整性。

使用这种方法可以:

  • 在任一轴上按给定的米移动任何(经纬度,长度)点。

Python 方法通过定义的米移动任何点。

def translate_latlong(lat,long,lat_translation_meters,long_translation_meters):
''' method to move any lat,long point by provided meters in lat and long direction.
params :
lat,long: lattitude and longitude in degrees as decimal values, e.g. 37.43609517497065, -122.17226450150885
lat_translation_meters: movement of point in meters in lattitude direction.
positive value: up move, negative value: down move
long_translation_meters: movement of point in meters in longitude direction.
positive value: left move, negative value: right move
'''
earth_radius = 6378.137


#Calculate top, which is lat_translation_meters above
m_lat = (1 / ((2 * math.pi / 360) * earth_radius)) / 1000;
lat_new = lat + (lat_translation_meters * m_lat)


#Calculate right, which is long_translation_meters right
m_long = (1 / ((2 * math.pi / 360) * earth_radius)) / 1000;  # 1 meter in degree
long_new = long + (long_translation_meters * m_long) / math.cos(lat * (math.pi / 180));
    

return lat_new,long_new

原来的海报上说: “所以我有50.0452345(x)和4.3242234(y) ,我想知道 x + 500米... ...”

我将假设他给出的 x 和 y 值的单位是米(而不是经度,纬度)。如果是这样,那么他声明测量到0.1微米,所以我将假设他需要类似的精度翻译输出。我也会假设“ + 500米”等等他的意思 正南北和正东西方向。 他提到了一个参考点: “基于一个坐标的2个新纬度”; 但他没有给经纬度 为了具体解释这个过程,我将给出 经度和纬度的角落 他要求的500米长的箱子 [经度30度,纬度30度]。

GRS80椭球面上的精确解是 用下面的函数集给出 (我为免费开源的 mac-pc 数学程序“ PARI”编写了这些代码 它允许设置任意数字的精度) :

\\=======Arc lengths along Latitude and Longitude and the respective scales:
dms(u)=[truncate(u),truncate((u-truncate(u))*60),((u-truncate(u))*60-truncate((u-truncate(u))*60))*60];
SpinEarthRadiansPerSec=7.292115e-5;\
GMearth=3986005e8;\
J2earth=108263e-8;\
re=6378137;\
ecc=solve(ecc=.0001,.9999,eccp=ecc/sqrt(1-ecc^2);qecc=(1+3/eccp^2)*atan(eccp)-3/eccp;ecc^2-(3*J2earth+4/15*SpinEarthRadiansPerSec^2*re^3/GMearth*ecc^3/qecc));\
e2=ecc^2;\
b2=1-e2;\
b=sqrt(b2);\
fl=1-b;\
rfl=1/fl;\
U0=GMearth/ecc/re*atan(eccp)+1/3*SpinEarthRadiansPerSec^2*re^2;\
HeightAboveEllipsoid=0;\
reh=re+HeightAboveEllipsoid;\
longscale(lat)=reh*Pi/648000/sqrt(1+b2*(tan(lat))^2);
latscale(lat)=reh*b*Pi/648000/(1-e2*(sin(lat))^2)^(3/2);
longarc(lat,long1,long2)=longscale(lat)*648000/Pi*(long2-long1);
latarc(lat1,lat2)=(intnum(th=lat1,lat2,sqrt(1-e2*(sin(th))^2))+e2/2*sin(2*lat1)/sqrt(1-e2*(sin(lat1))^2)-e2/2*sin(2*lat2)/sqrt(1-e2*(sin(lat2))^2))*reh;
\\=======

然后我插入参考点[30,30] 在 PARI 命令提示符下插入这些函数 并用 PARI 解出了 +/-500米外的点 给出了两个新的经度和 两个新的纬度,原来的海报要求。 以下输入和输出显示:

? dms(solve(x=29,31,longarc(30*Pi/180,30*Pi/180,x*Pi/180)+500))
cpu time = 1 ms, real time = 1 ms.
%1172 = [29, 59, 41.3444979398934670450280297216509190843055]
? dms(solve(x=29,31,longarc(30*Pi/180,30*Pi/180,x*Pi/180)-500))
cpu time = 1 ms, real time = 1 ms.
%1173 = [30, 0, 18.6555020601065329549719702783490809156945]
? dms(solve(x=29,31,latarc(30*Pi/180,x*Pi/180)+500))
cpu time = 1,357 ms, real time = 1,358 ms.
%1174 = [29, 59, 43.7621925447500548285775757329518579545513]
? dms(solve(x=29,31,latarc(30*Pi/180,x*Pi/180)-500))
cpu time = 1,365 ms, real time = 1,368 ms.
%1175 = [30, 0, 16.2377963202802863245716034907838199823349]
?