画圆时如何将米准确转换为经度或纬度
How to accurately convert meters to longitude or latitude when drawing a circle
注意:问题不是 Leaflet 特有的,而是一般的 GIS。
我想在地图上画一条弧线。我有一个生成多边形点的函数,它适用于 canvas 例如,但不适用于 Lng,Lat 地图。
问题是我无法弄清楚如何将 inner/outer 半径从米转换为度数(如 lng/lat),到目前为止我尝试的看起来更像椭圆而不是圆形。
如何将地球上任意一点(两极除外)的米准确转换为经度或纬度?
这是我在 canvas.
上尝试(有效)的方法
$(document).ready(function() {
var d_canvas = document.getElementById('canvas');
var c2 = d_canvas.getContext('2d');
c2.fillStyle = '#f00';
c2.beginPath();
var fromDeg = 0;
var toDeg = 90;
var fromRad = getAngle(fromDeg);
var toRad = getAngle(toDeg);
var segments = 100;
var step = getAngle(toDeg-fromDeg)/segments;
var x = 250;
var y = 250;
var outR = 250;
var inR = 230;
c2.moveTo(x+(Math.sin(fromRad)*inR),y-(Math.cos(fromRad)*inR));
//c2.moveTo(x,y);
for (var i = fromRad; i<=toRad; i=i+step){
c2.lineTo(x+(Math.sin(i)*inR),y-(Math.cos(i)*inR));
}
//c2.closePath();
for (var i = toRad; i>=fromRad; i=i-step){
c2.lineTo(x+(Math.sin(i)*outR),y-(Math.cos(i)*outR));
}
c2.lineTo(x+(Math.sin(fromRad)*inR),y-(Math.cos(fromRad)*inR));
//c2.closePath();
c2.stroke();
});
function getAngle(deg){
var val = 2*(deg/360);
return Math.PI*val;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="500"></canvas>
这是我在 Leaflet 地图上尝试过的(效果不佳)。
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm);
// Script for adding marker on map click
L.polygon(getPolygon()).addTo(map);
function getPolygon() {
var fromDeg = 0;
var toDeg = 90;
var fromRad = getAngle(fromDeg);
var toRad = getAngle(toDeg);
var segments = 100;
var step = getAngle(toDeg - fromDeg) / segments;
var y = 150.84229;
var x = 59.55416;
var outR = 0.05; // <------ should be dynamic?
var inR = 0.025; // <------ this also?
var polygon = [];
polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]);
for (var i = fromRad; i <= toRad; i = i + step) {
polygon.push([x + (Math.sin(i) * inR), y + (Math.cos(i) * inR)]);
}
//c2.closePath();
for (var i = toRad; i >= fromRad; i = i - step) {
polygon.push([x + (Math.sin(i) * outR), y + (Math.cos(i) * outR)]);
}
polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]);
return polygon;
}
function getAngle(deg) {
var val = 2 * (deg / 360);
return Math.PI * val;
}
#map {
height: 500px;
width: 80%;
}
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet" />
<script src="http://unpkg.com/leaflet-arc/bin/leaflet-arc.min.js"></script>
<div id="map"></div>
所以你原来的问题是
How to accurately convert meters to longitude or latitude at any point on earth (except the poles)?
但我的大脑将其解读为
Given a [lat, lng]
point and a distance d
in meters, how to calculate a second [lat2, lng2]
point which is d
meters away from the first point?
如果您知道一些 GIS 行话,就等同于询问
How do I solve the direct geodesic problem?
答案涉及椭圆体、大圆等数学概念
但鉴于您正在使用 Javascript 和 Leaflet,我将直接跳到实际实施。
如果你需要一个超精确的答案,你想看看the JS implementation of GeographicLib,以及它解决直接测地线问题的方法。
如果您真的不关心准确性(特别是不关心极点处的准确性),您想看看 cheap-ruler,特别是它的 destination(p, dist, bearing)
方法。
还有更多解决方案,比如使用以点为中心的等距地图投影,或者测地线问题的其他一些实现,或者一些turf.js技巧,或者用类似的方法在JS之外创建几何,或其他。
这个问题已经解决了,所以我建议使用任何现有的解决方案。
这解决了问题
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm);
// Script for adding marker on map click
L.polygon(getPolygon()).addTo(map);
function getPolygon() {
var fromDeg = 0;
var toDeg = 120;
var lat = 59.56667;
var lon = 150.80000;
var outR = 200;
var inR = 180;
var polygon = [];
for (var i = fromDeg; i <= toDeg; i++) {
polygon.push(getPoint(lat, lon, inR, i));
}
for (var i = toDeg; i >= fromDeg; i--) {
polygon.push(getPoint(lat, lon, outR, i));
}
polygon.push(getPoint(lat, lon, inR, fromDeg));
return polygon;
}
/*************************
* The solution
*************************/
function getPoint(lat, lon, r, deg) {
lat2 = (r / 111230) * Math.cos(deg2rad(deg));
lat2 += lat;
lon2 = (r / 111230) * Math.sin(deg2rad(deg));
lon2 = lon2 * (1 / Math.cos(deg2rad(lat2)));
lon2 += lon;
return [lat2, lon2];
}
function deg2rad(deg) {
return deg * (Math.PI / 180);
}
#map {
height: 500px;
width: 80%;
}
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet"/>
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<div id="map"></div>
注意:问题不是 Leaflet 特有的,而是一般的 GIS。
我想在地图上画一条弧线。我有一个生成多边形点的函数,它适用于 canvas 例如,但不适用于 Lng,Lat 地图。
问题是我无法弄清楚如何将 inner/outer 半径从米转换为度数(如 lng/lat),到目前为止我尝试的看起来更像椭圆而不是圆形。
如何将地球上任意一点(两极除外)的米准确转换为经度或纬度?
这是我在 canvas.
上尝试(有效)的方法$(document).ready(function() {
var d_canvas = document.getElementById('canvas');
var c2 = d_canvas.getContext('2d');
c2.fillStyle = '#f00';
c2.beginPath();
var fromDeg = 0;
var toDeg = 90;
var fromRad = getAngle(fromDeg);
var toRad = getAngle(toDeg);
var segments = 100;
var step = getAngle(toDeg-fromDeg)/segments;
var x = 250;
var y = 250;
var outR = 250;
var inR = 230;
c2.moveTo(x+(Math.sin(fromRad)*inR),y-(Math.cos(fromRad)*inR));
//c2.moveTo(x,y);
for (var i = fromRad; i<=toRad; i=i+step){
c2.lineTo(x+(Math.sin(i)*inR),y-(Math.cos(i)*inR));
}
//c2.closePath();
for (var i = toRad; i>=fromRad; i=i-step){
c2.lineTo(x+(Math.sin(i)*outR),y-(Math.cos(i)*outR));
}
c2.lineTo(x+(Math.sin(fromRad)*inR),y-(Math.cos(fromRad)*inR));
//c2.closePath();
c2.stroke();
});
function getAngle(deg){
var val = 2*(deg/360);
return Math.PI*val;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="500"></canvas>
这是我在 Leaflet 地图上尝试过的(效果不佳)。
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm);
// Script for adding marker on map click
L.polygon(getPolygon()).addTo(map);
function getPolygon() {
var fromDeg = 0;
var toDeg = 90;
var fromRad = getAngle(fromDeg);
var toRad = getAngle(toDeg);
var segments = 100;
var step = getAngle(toDeg - fromDeg) / segments;
var y = 150.84229;
var x = 59.55416;
var outR = 0.05; // <------ should be dynamic?
var inR = 0.025; // <------ this also?
var polygon = [];
polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]);
for (var i = fromRad; i <= toRad; i = i + step) {
polygon.push([x + (Math.sin(i) * inR), y + (Math.cos(i) * inR)]);
}
//c2.closePath();
for (var i = toRad; i >= fromRad; i = i - step) {
polygon.push([x + (Math.sin(i) * outR), y + (Math.cos(i) * outR)]);
}
polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]);
return polygon;
}
function getAngle(deg) {
var val = 2 * (deg / 360);
return Math.PI * val;
}
#map {
height: 500px;
width: 80%;
}
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet" />
<script src="http://unpkg.com/leaflet-arc/bin/leaflet-arc.min.js"></script>
<div id="map"></div>
所以你原来的问题是
How to accurately convert meters to longitude or latitude at any point on earth (except the poles)?
但我的大脑将其解读为
Given a
[lat, lng]
point and a distanced
in meters, how to calculate a second[lat2, lng2]
point which isd
meters away from the first point?
如果您知道一些 GIS 行话,就等同于询问
How do I solve the direct geodesic problem?
答案涉及椭圆体、大圆等数学概念
但鉴于您正在使用 Javascript 和 Leaflet,我将直接跳到实际实施。
如果你需要一个超精确的答案,你想看看the JS implementation of GeographicLib,以及它解决直接测地线问题的方法。
如果您真的不关心准确性(特别是不关心极点处的准确性),您想看看 cheap-ruler,特别是它的 destination(p, dist, bearing)
方法。
还有更多解决方案,比如使用以点为中心的等距地图投影,或者测地线问题的其他一些实现,或者一些turf.js技巧,或者用类似的方法在JS之外创建几何,或其他。
这个问题已经解决了,所以我建议使用任何现有的解决方案。
这解决了问题
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osmAttrib = '© <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
});
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm);
// Script for adding marker on map click
L.polygon(getPolygon()).addTo(map);
function getPolygon() {
var fromDeg = 0;
var toDeg = 120;
var lat = 59.56667;
var lon = 150.80000;
var outR = 200;
var inR = 180;
var polygon = [];
for (var i = fromDeg; i <= toDeg; i++) {
polygon.push(getPoint(lat, lon, inR, i));
}
for (var i = toDeg; i >= fromDeg; i--) {
polygon.push(getPoint(lat, lon, outR, i));
}
polygon.push(getPoint(lat, lon, inR, fromDeg));
return polygon;
}
/*************************
* The solution
*************************/
function getPoint(lat, lon, r, deg) {
lat2 = (r / 111230) * Math.cos(deg2rad(deg));
lat2 += lat;
lon2 = (r / 111230) * Math.sin(deg2rad(deg));
lon2 = lon2 * (1 / Math.cos(deg2rad(lat2)));
lon2 += lon;
return [lat2, lon2];
}
function deg2rad(deg) {
return deg * (Math.PI / 180);
}
#map {
height: 500px;
width: 80%;
}
<link href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" rel="stylesheet"/>
<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
<div id="map"></div>