2016-12-06 2 views
2

Примечание. Проблема не относится к Листовке, но ГИС вообще.Как точно преобразовать метры в долготу или широту при рисовании круга

Я пытаюсь нарисовать дугу на карте. У меня есть функция для создания точек многоугольника, и она работает, например, на холсте, но не на Lng, карте Lat.

Проблема в том, что я не могу понять, как преобразовать внутренний/внешний радиус из Метров в градусы (как в lng/lat), то, что я пробовал до сих пор, выглядит более эллиптическим, чем круговым.

Как точно преобразовать счетчики в долготу или широту в любой точке земли (кроме полюсов)?

Вот что я пробовал (работает) на холсте.

$(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){ 
 
    \t c2.lineTo(x+(Math.sin(i)*inR),y-(Math.cos(i)*inR)); 
 
    } 
 
    //c2.closePath(); 
 
    for (var i = toRad; i>=fromRad; i=i-step){ 
 
    \t 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){ 
 
\t var val = 2*(deg/360); 
 
    \t 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>

И вот что я пытался (dosn't хорошо работать) на карте Листовка.

\t \t var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png', 
 
\t \t osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors', 
 
\t \t osm = L.tileLayer(osmUrl, { 
 
\t \t  maxZoom: 18, 
 
\t \t  attribution: osmAttrib 
 
\t \t }); 
 

 
\t \t // initialize the map on the "map" div with a given center and zoom 
 
\t \t var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm); 
 

 
\t \t // Script for adding marker on map click 
 
\t \t L.polygon(getPolygon()).addTo(map); 
 

 
\t \t function getPolygon() { 
 
\t \t var fromDeg = 0; 
 
\t \t var toDeg = 90; 
 
\t \t var fromRad = getAngle(fromDeg); 
 
\t \t var toRad = getAngle(toDeg); 
 
\t \t var segments = 100; 
 
\t \t var step = getAngle(toDeg - fromDeg)/segments; 
 
\t \t var y = 150.84229; 
 
\t \t var x = 59.55416; 
 
\t \t var outR = 0.05; // <------ should be dynamic? 
 
\t \t var inR = 0.025; // <------ this also? 
 
\t \t var polygon = []; 
 
\t \t polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]); 
 
\t \t for (var i = fromRad; i <= toRad; i = i + step) { 
 
\t \t  polygon.push([x + (Math.sin(i) * inR), y + (Math.cos(i) * inR)]); 
 
\t \t } 
 
\t \t //c2.closePath(); 
 
\t \t for (var i = toRad; i >= fromRad; i = i - step) { 
 
\t \t  polygon.push([x + (Math.sin(i) * outR), y + (Math.cos(i) * outR)]); 
 
\t \t } 
 
\t \t polygon.push([x + (Math.sin(fromRad) * inR), y + (Math.cos(fromRad) * inR)]); 
 
\t \t return polygon; 
 
\t \t } 
 

 
\t \t function getAngle(deg) { 
 
\t \t var val = 2 * (deg/360); 
 
\t \t return Math.PI * val; 
 
\t \t }
#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>

ответ

4

Так что ваш первоначальный вопрос является

Как точно конвертировать метров до долготы или широты в любой точке на земле (кроме полюсов)?

Но мой мозг читает, что, как

Учитывая [lat, lng] точку и расстояние d в метрах, как вычислить вторую [lat2, lng2] точку, которая d метрах от первой точки?

Что, если вы знаете, некоторые ГИС жаргон, это то же самое, что спрашивать

Как решить direct geodesic problem?

Ответ включает в себя математические концепции, такие как эллипсоиды и большие круги.

Но, учитывая, что вы работаете с Javascript и листом, я просто перейду к практическим реализациям.

Если вам нужен суперточный ответ, вы хотите посмотреть на the JS implementation of GeographicLib и его методы для решения прямой геодезической проблемы.

Если вы не уверены в точности (и особенно не заботитесь о точности на полюсах), вы хотите взглянуть на cheap-ruler и, в частности, на его метод destination(p, dist, bearing).

Существует больше решений, таких как использование эквидистантной проекции карты с центром в точке или некоторых других реализаций геодезических проблем или обтекания обтекания или создание геометрий вне JS с помощью аналогичных методов или что-то еще.

Эта проблема уже решена, поэтому я советую использовать любые существующие решения.

+0

Спасибо за ответ, я читаю через ваши ссылки. – Aus

+0

Это также сработало http://jsfiddle.net/czguhjrx/7/ – Aus

+0

. Посмотрите на мое решение ниже и посмотрите, насколько это точно для радиуса круга/дуги менее 100 км? – Aus

1

Это решило проблему

\t \t var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png', 
 
\t \t osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors', 
 
\t \t osm = L.tileLayer(osmUrl, { 
 
\t \t  maxZoom: 18, 
 
\t \t  attribution: osmAttrib 
 
\t \t }); 
 

 
\t \t // initialize the map on the "map" div with a given center and zoom 
 
\t \t var map = L.map('map').setView([59.56667, 150.80000], 12).addLayer(osm); 
 

 
\t \t // Script for adding marker on map click 
 
\t \t L.polygon(getPolygon()).addTo(map); 
 

 
\t \t function getPolygon() { 
 
\t \t var fromDeg = 0; 
 
\t \t var toDeg = 120; 
 
\t \t var lat = 59.56667; 
 
\t \t var lon = 150.80000; 
 
\t \t var outR = 200; 
 
\t \t var inR = 180; 
 
\t \t var polygon = []; 
 
\t \t for (var i = fromDeg; i <= toDeg; i++) { 
 
\t \t  polygon.push(getPoint(lat, lon, inR, i)); 
 
\t \t } 
 
\t \t for (var i = toDeg; i >= fromDeg; i--) { 
 
\t \t  polygon.push(getPoint(lat, lon, outR, i)); 
 
\t \t } 
 
\t \t polygon.push(getPoint(lat, lon, inR, fromDeg)); 
 
\t \t return polygon; 
 
\t \t } 
 
     /************************* 
 
     * The solution 
 
     *************************/ 
 
\t \t function getPoint(lat, lon, r, deg) { 
 
\t \t lat2 = (r/111230) * Math.cos(deg2rad(deg)); 
 
\t \t lat2 += lat; 
 
\t \t lon2 = (r/111230) * Math.sin(deg2rad(deg)); 
 
\t \t lon2 = lon2 * (1/Math.cos(deg2rad(lat2))); 
 
\t \t lon2 += lon; 
 
\t \t return [lat2, lon2]; 
 
\t \t } 
 

 
\t \t function deg2rad(deg) { 
 
\t \t return deg * (Math.PI/180); 
 
\t \t }
#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>

Смежные вопросы