如果我知道中心和左上角的 GPS 位置,如何获得矩形的纬度和经度?
How do I get the latitude and longitude of a rectangle if I know the center and top left GPS positions?
背景:
我正在尝试使用 Google 地图 ground overlay 但我们缺少 GPS 位置。
我们有一张地图要叠加在 Google 地图屏幕截图上。从这张截图中我们记录了左上角和居中位置。
我们需要右下角的位置来准确叠加这些图像。见下文:
最初的想法是找到两点之间的差异并将其添加到中心点。
尝试的逻辑:
在JavaScript中:
var topLeft = [-32.8830055, 151.686214];
var centerCenter = [-32.9293803, 151.756686];
var difference1 = centerCenter[0] - ( (topLeft[0] - centerCenter[0] ) ) ;
var difference2 = centerCenter[1] - ( (topLeft[1] - centerCenter[1] ) ) ;
// being bottom right this should be "bigger" than above values
// outputs [-32.97575509999999, 151.827158];
var bottomRight = [difference1 , difference2];
问题:
然而,这似乎是地球曲线将简单数学抛出门外的地方。我猜下面发生的事情就是原因。
所以假设我有一个矩形叠加层并且我知道左上角点和中心点我可以算出右下角点的纬度和经度吗 即 X 在上图。注意我不知道这个矩形的真实世界距离。
注意:我也知道我必须将这些更改为 NW / SE 才能使用地面覆盖层。
您可能需要 Haversine 公式来进行此类计算。所涉及的数学显然比 SO 答案的典型水平更高,因此您的问题实际上可能属于 gis 或数学堆栈交换,一些更有经验的 SO 用户可能会为您提供更详细的答案/示例。
您是否反对使用已经支持计算中心点的 Haversine 的库? (启动测试)
查看 Geolib:https://github.com/manuelbieh/Geolib
var center = geolib.getCenter([
{latitude: 52.516272, longitude: 13.377722},
{latitude: 51.515, longitude: 7.453619},
{latitude: 51.503333, longitude: -0.119722}
]);
console.log(center);
// Output:
//
// {
// "latitude": "52.009802",
// "longitude": "6.629000",
// "distance": 932.209
// }
您可以玩的代码笔演示:http://codepen.io/anon/pen/grbGrz/?editors=1010
您可以随时将其精简到只需要您需要的功能。
以免从查询的开头开始。你有两个 latlng,现在你想得到矩形的 latlng。
我们将先进行计算部分,然后进行编程部分。假设是-
中心点 = e
左上 = A
右上=B
右下 = C
左下 = D
AD=f的中点
AB=g 的中点
计算部分
location g 参数-lat-A.lat, long-e.long
location f参数-lat-e.lat, long-A.long
A 到 g 的距离 = A.distanceTo(g)
A 到 f 的距离 = A.distanceTo(f)
点 B = 来自 A 的 2Ag
点 C = B 的 2Af
点 D = A 的 2Af
编程部分
LatLng A = null, B = null, C = null, D = null, e = null, f = null, g = null,temp=null;
e.latitude = your center latitude value;
e.longitude = your center longitude value;
A.latitude=your top left point latitude value;
A.longitude=your top left point longitude value;
f.latitude = e.latitude;
f.longitude = A.longitude;
g.latitude = A.latitude;
g.longitude = e.longitude;
double[] Ag = new double[1];
double[] Af = new double[1];
Location.distanceBetween(A.latitude, A.longitude, g.latitude, g.longitude, Ag);
Location.distanceBetween(A.latitude, A.longitude, f.latitude, f.longitude, Af);
temp=getDestinationPoint(A,90,(2*Ag));
B.latitude=temp.latitude;
B.longitude=temp.longitude;
temp=getDestinationPoint(B,180,(2*Af));
C.latitude=temp.latitude;
C.longitude=temp.longitude;
temp=getDestinationPoint(A,180,(2*Af));
D.latitude=temp.latitude;
D.longitude=temp.longitude;
private LatLng getDestinationPoint (LatLng source,double brng, double dist){
dist = dist / 6371;
brng = Math.toRadians(brng);
double lat1 = Math.toRadians(source.latitude), lon1 = Math.toRadians(source.longitude);
double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
Math.cos(lat1),
Math.cos(dist) - Math.sin(lat1) *
Math.sin(lat2));
if (Double.isNaN(lat2) || Double.isNaN(lon2)) {
return null;
}
return new LatLng(Math.toDegrees(lat2), Math.toDegrees(lon2));
}
说明
点f和g分别是直线AD和AB的中点。我们可以通过改变 A 点和 e 点的经纬度值来得到它。通过这两个长度(Af和Ag)我们可以根据需要得到矩形的四个latlng点。
谢谢
方法(使用几何库):
计算从西北到中心的航向
google.maps.geometry.spherical.computeHeading(northwest, center);
计算从西北到中心的距离
google.maps.geometry.spherical.computeDistanceBetween(northwest, center);
使用
计算东南方向
google.maps.geometry.spherical.computeOffset(center,
calculatedDistance,
calculatedHeading);
function initialize() {
var nw = new google.maps.LatLng(62.400471, -150.287132),
center = new google.maps.LatLng(62.341145, -150.14637),
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 9,
center: center
}),
heading, distance, se;
heading = google.maps.geometry.spherical.computeHeading(nw, center);
distance = google.maps.geometry.spherical.computeDistanceBetween(nw, center);
se = google.maps.geometry.spherical.computeOffset(center, distance, heading);
new google.maps.Marker({
map: map,
position: center
});
new google.maps.Marker({
map: map,
position: nw
});
new google.maps.Marker({
map: map,
position: se
});
new google.maps.GroundOverlay(
'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png', {
north: nw.lat(),
south: se.lat(),
west: nw.lng(),
east: se.lng()
}, {
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map_canvas {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map_canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
使用下面的 javascript 函数获取基于中心的矩形列表 lat/long,distance.latLngArr 是矩形点列表。
Number.prototype.degreeToRadius = function () {
return this * (Math.PI / 180);
};
Number.prototype.radiusToDegree = function () {
return (180 * this) / Math.PI;
};
function getBoundingBox(fsLatitude, fsLongitude, fiDistanceInKM) {
if (fiDistanceInKM == null || fiDistanceInKM == undefined || fiDistanceInKM == 0)
fiDistanceInKM = 1;
var MIN_LAT, MAX_LAT, MIN_LON, MAX_LON, ldEarthRadius, ldDistanceInRadius, lsLatitudeInDegree, lsLongitudeInDegree,
lsLatitudeInRadius, lsLongitudeInRadius, lsMinLatitude, lsMaxLatitude, lsMinLongitude, lsMaxLongitude, deltaLon;
// coordinate limits
MIN_LAT = (-90).degreeToRadius();
MAX_LAT = (90).degreeToRadius();
MIN_LON = (-180).degreeToRadius();
MAX_LON = (180).degreeToRadius();
// Earth's radius (km)
ldEarthRadius = 6378.1;
// angular distance in radians on a great circle
ldDistanceInRadius = fiDistanceInKM / ldEarthRadius;
// center point coordinates (deg)
lsLatitudeInDegree = fsLatitude;
lsLongitudeInDegree = fsLongitude;
// center point coordinates (rad)
lsLatitudeInRadius = lsLatitudeInDegree.degreeToRadius();
lsLongitudeInRadius = lsLongitudeInDegree.degreeToRadius();
// minimum and maximum latitudes for given distance
lsMinLatitude = lsLatitudeInRadius - ldDistanceInRadius;
lsMaxLatitude = lsLatitudeInRadius + ldDistanceInRadius;
// minimum and maximum longitudes for given distance
lsMinLongitude = void 0;
lsMaxLongitude = void 0;
// define deltaLon to help determine min and max longitudes
deltaLon = Math.asin(Math.sin(ldDistanceInRadius) / Math.cos(lsLatitudeInRadius));
if (lsMinLatitude > MIN_LAT && lsMaxLatitude < MAX_LAT) {
lsMinLongitude = lsLongitudeInRadius - deltaLon;
lsMaxLongitude = lsLongitudeInRadius + deltaLon;
if (lsMinLongitude < MIN_LON) {
lsMinLongitude = lsMinLongitude + 2 * Math.PI;
}
if (lsMaxLongitude > MAX_LON) {
lsMaxLongitude = lsMaxLongitude - 2 * Math.PI;
}
}
// a pole is within the given distance
else {
lsMinLatitude = Math.max(lsMinLatitude, MIN_LAT);
lsMaxLatitude = Math.min(lsMaxLatitude, MAX_LAT);
lsMinLongitude = MIN_LON;
lsMaxLongitude = MAX_LON;
}
return [
lsMinLatitude.radiusToDegree(),
lsMinLongitude.radiusToDegree(),
lsMaxLatitude.radiusToDegree(),
lsMaxLongitude.radiusToDegree()
];
};
使用下面的代码生成一个 lat/long 矩形数组。
var lsRectangleLatLong = getBoundingBox(parseFloat(latitude), parseFloat(longitude), lsDistance);
if (lsRectangleLatLong != null && lsRectangleLatLong != undefined) {
latLngArr.push({ lat: lsRectangleLatLong[0], lng: lsRectangleLatLong[1] });
latLngArr.push({ lat: lsRectangleLatLong[0], lng: lsRectangleLatLong[3] });
latLngArr.push({ lat: lsRectangleLatLong[2], lng: lsRectangleLatLong[3] });
latLngArr.push({ lat: lsRectangleLatLong[2], lng: lsRectangleLatLong[1] });
}
背景:
我正在尝试使用 Google 地图 ground overlay 但我们缺少 GPS 位置。
我们有一张地图要叠加在 Google 地图屏幕截图上。从这张截图中我们记录了左上角和居中位置。
我们需要右下角的位置来准确叠加这些图像。见下文:
最初的想法是找到两点之间的差异并将其添加到中心点。
尝试的逻辑:
在JavaScript中:
var topLeft = [-32.8830055, 151.686214];
var centerCenter = [-32.9293803, 151.756686];
var difference1 = centerCenter[0] - ( (topLeft[0] - centerCenter[0] ) ) ;
var difference2 = centerCenter[1] - ( (topLeft[1] - centerCenter[1] ) ) ;
// being bottom right this should be "bigger" than above values
// outputs [-32.97575509999999, 151.827158];
var bottomRight = [difference1 , difference2];
问题:
然而,这似乎是地球曲线将简单数学抛出门外的地方。我猜下面发生的事情就是原因。
所以假设我有一个矩形叠加层并且我知道左上角点和中心点我可以算出右下角点的纬度和经度吗 即 X 在上图。注意我不知道这个矩形的真实世界距离。
注意:我也知道我必须将这些更改为 NW / SE 才能使用地面覆盖层。
您可能需要 Haversine 公式来进行此类计算。所涉及的数学显然比 SO 答案的典型水平更高,因此您的问题实际上可能属于 gis 或数学堆栈交换,一些更有经验的 SO 用户可能会为您提供更详细的答案/示例。
您是否反对使用已经支持计算中心点的 Haversine 的库? (启动测试)
查看 Geolib:https://github.com/manuelbieh/Geolib
var center = geolib.getCenter([
{latitude: 52.516272, longitude: 13.377722},
{latitude: 51.515, longitude: 7.453619},
{latitude: 51.503333, longitude: -0.119722}
]);
console.log(center);
// Output:
//
// {
// "latitude": "52.009802",
// "longitude": "6.629000",
// "distance": 932.209
// }
您可以玩的代码笔演示:http://codepen.io/anon/pen/grbGrz/?editors=1010
您可以随时将其精简到只需要您需要的功能。
以免从查询的开头开始。你有两个 latlng,现在你想得到矩形的 latlng。
我们将先进行计算部分,然后进行编程部分。假设是-
中心点 = e
左上 = A
右上=B
右下 = C
左下 = D
AD=f的中点
AB=g 的中点
计算部分
location g 参数-lat-A.lat, long-e.long
location f参数-lat-e.lat, long-A.long
A 到 g 的距离 = A.distanceTo(g)
A 到 f 的距离 = A.distanceTo(f)
点 B = 来自 A 的 2Ag
点 C = B 的 2Af
点 D = A 的 2Af
编程部分
LatLng A = null, B = null, C = null, D = null, e = null, f = null, g = null,temp=null;
e.latitude = your center latitude value;
e.longitude = your center longitude value;
A.latitude=your top left point latitude value;
A.longitude=your top left point longitude value;
f.latitude = e.latitude;
f.longitude = A.longitude;
g.latitude = A.latitude;
g.longitude = e.longitude;
double[] Ag = new double[1];
double[] Af = new double[1];
Location.distanceBetween(A.latitude, A.longitude, g.latitude, g.longitude, Ag);
Location.distanceBetween(A.latitude, A.longitude, f.latitude, f.longitude, Af);
temp=getDestinationPoint(A,90,(2*Ag));
B.latitude=temp.latitude;
B.longitude=temp.longitude;
temp=getDestinationPoint(B,180,(2*Af));
C.latitude=temp.latitude;
C.longitude=temp.longitude;
temp=getDestinationPoint(A,180,(2*Af));
D.latitude=temp.latitude;
D.longitude=temp.longitude;
private LatLng getDestinationPoint (LatLng source,double brng, double dist){
dist = dist / 6371;
brng = Math.toRadians(brng);
double lat1 = Math.toRadians(source.latitude), lon1 = Math.toRadians(source.longitude);
double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
Math.cos(lat1),
Math.cos(dist) - Math.sin(lat1) *
Math.sin(lat2));
if (Double.isNaN(lat2) || Double.isNaN(lon2)) {
return null;
}
return new LatLng(Math.toDegrees(lat2), Math.toDegrees(lon2));
}
说明
点f和g分别是直线AD和AB的中点。我们可以通过改变 A 点和 e 点的经纬度值来得到它。通过这两个长度(Af和Ag)我们可以根据需要得到矩形的四个latlng点。
谢谢
方法(使用几何库):
计算从西北到中心的航向
google.maps.geometry.spherical.computeHeading(northwest, center);
计算从西北到中心的距离
google.maps.geometry.spherical.computeDistanceBetween(northwest, center);
使用
计算东南方向google.maps.geometry.spherical.computeOffset(center, calculatedDistance, calculatedHeading);
function initialize() {
var nw = new google.maps.LatLng(62.400471, -150.287132),
center = new google.maps.LatLng(62.341145, -150.14637),
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 9,
center: center
}),
heading, distance, se;
heading = google.maps.geometry.spherical.computeHeading(nw, center);
distance = google.maps.geometry.spherical.computeDistanceBetween(nw, center);
se = google.maps.geometry.spherical.computeOffset(center, distance, heading);
new google.maps.Marker({
map: map,
position: center
});
new google.maps.Marker({
map: map,
position: nw
});
new google.maps.Marker({
map: map,
position: se
});
new google.maps.GroundOverlay(
'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png', {
north: nw.lat(),
south: se.lat(),
west: nw.lng(),
east: se.lng()
}, {
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map_canvas {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map_canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
使用下面的 javascript 函数获取基于中心的矩形列表 lat/long,distance.latLngArr 是矩形点列表。
Number.prototype.degreeToRadius = function () {
return this * (Math.PI / 180);
};
Number.prototype.radiusToDegree = function () {
return (180 * this) / Math.PI;
};
function getBoundingBox(fsLatitude, fsLongitude, fiDistanceInKM) {
if (fiDistanceInKM == null || fiDistanceInKM == undefined || fiDistanceInKM == 0)
fiDistanceInKM = 1;
var MIN_LAT, MAX_LAT, MIN_LON, MAX_LON, ldEarthRadius, ldDistanceInRadius, lsLatitudeInDegree, lsLongitudeInDegree,
lsLatitudeInRadius, lsLongitudeInRadius, lsMinLatitude, lsMaxLatitude, lsMinLongitude, lsMaxLongitude, deltaLon;
// coordinate limits
MIN_LAT = (-90).degreeToRadius();
MAX_LAT = (90).degreeToRadius();
MIN_LON = (-180).degreeToRadius();
MAX_LON = (180).degreeToRadius();
// Earth's radius (km)
ldEarthRadius = 6378.1;
// angular distance in radians on a great circle
ldDistanceInRadius = fiDistanceInKM / ldEarthRadius;
// center point coordinates (deg)
lsLatitudeInDegree = fsLatitude;
lsLongitudeInDegree = fsLongitude;
// center point coordinates (rad)
lsLatitudeInRadius = lsLatitudeInDegree.degreeToRadius();
lsLongitudeInRadius = lsLongitudeInDegree.degreeToRadius();
// minimum and maximum latitudes for given distance
lsMinLatitude = lsLatitudeInRadius - ldDistanceInRadius;
lsMaxLatitude = lsLatitudeInRadius + ldDistanceInRadius;
// minimum and maximum longitudes for given distance
lsMinLongitude = void 0;
lsMaxLongitude = void 0;
// define deltaLon to help determine min and max longitudes
deltaLon = Math.asin(Math.sin(ldDistanceInRadius) / Math.cos(lsLatitudeInRadius));
if (lsMinLatitude > MIN_LAT && lsMaxLatitude < MAX_LAT) {
lsMinLongitude = lsLongitudeInRadius - deltaLon;
lsMaxLongitude = lsLongitudeInRadius + deltaLon;
if (lsMinLongitude < MIN_LON) {
lsMinLongitude = lsMinLongitude + 2 * Math.PI;
}
if (lsMaxLongitude > MAX_LON) {
lsMaxLongitude = lsMaxLongitude - 2 * Math.PI;
}
}
// a pole is within the given distance
else {
lsMinLatitude = Math.max(lsMinLatitude, MIN_LAT);
lsMaxLatitude = Math.min(lsMaxLatitude, MAX_LAT);
lsMinLongitude = MIN_LON;
lsMaxLongitude = MAX_LON;
}
return [
lsMinLatitude.radiusToDegree(),
lsMinLongitude.radiusToDegree(),
lsMaxLatitude.radiusToDegree(),
lsMaxLongitude.radiusToDegree()
];
};
使用下面的代码生成一个 lat/long 矩形数组。
var lsRectangleLatLong = getBoundingBox(parseFloat(latitude), parseFloat(longitude), lsDistance);
if (lsRectangleLatLong != null && lsRectangleLatLong != undefined) {
latLngArr.push({ lat: lsRectangleLatLong[0], lng: lsRectangleLatLong[1] });
latLngArr.push({ lat: lsRectangleLatLong[0], lng: lsRectangleLatLong[3] });
latLngArr.push({ lat: lsRectangleLatLong[2], lng: lsRectangleLatLong[3] });
latLngArr.push({ lat: lsRectangleLatLong[2], lng: lsRectangleLatLong[1] });
}