我正在开发一个应用程序,我有一个圆心和半径,我正在Leaflet的帮助下绘制圆圈。
我在圆周的最北端放置了一个标记,使其可以拖动。
var circle = L.circle(coords, radius).addTo(map);
convertRadiusToLatitude = parseInt(response.radius)/111111;
var coordsOnRadius = [parseFloat(response.lat) + convertRadiusToLatitude, parseFloat(response.long)];
var markerOnRadius = L.marker(coordsOnRadius, {draggable: true}).addTo(map);
现在,这会将标记添加到圆周上,现在我希望它只能在我使用参数方程的圆周上拖动。
参数方程式
x = Xc + R * cos(theta)
y = Yc + R * sin(theta)
拖动代码
markerOnRadius.on('drag', function(e){
bearing = marker.getLatLng().bearingTo(markerOnRadius.getLatLng());
var markerOnRadiusX = parseFloat(response.lat) + ((0.000009 * parseFloat(response.radius)) * Math.cos( toRad(bearing) ));
var markerOnRadiusY = parseFloat(response.long) + ((0.000009 * parseFloat(response.radius)) * Math.sin( toRad(bearing) ));
markerOnRadius.setLatLng([markerOnRadiusX, markerOnRadiusY]);
});
bearingTo
方法:
L.LatLng.prototype.bearingTo = function(other) {
var d2r = L.LatLng.DEG_TO_RAD;
var r2d = L.LatLng.RAD_TO_DEG;
var lat1 = this.lat * d2r;
var lat2 = other.lat * d2r;
var dLon = (other.lng-this.lng) * d2r;
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x);
brng = parseInt( brng * r2d );
brng = (brng + 360) % 360;
return brng;
};
问题
当我开始拖动标记时,此代码工作正常并将其拖回到拖动标记的方位的圆周上。但是存在一个问题,圆周上的坐标略微偏离并且就经度而言。当轴承为0(北)时,坐标是完美的,但是当它是90(东)时,经度略小于标记在圆周上的经度。
再次在180(南方),坐标是完美的,但在270(西),计算的经度稍微减少,标记再次倾向于半径。
所以基本上如果你想象拖动的标记,它会在北端完美地开始并开始进入圆圈内部随着轴承略微增加直到它达到90,然后再次开始向圆周方向移动直到180再次完美
如果得到它的要点,它就更像椭圆。
有谁能告诉我为什么经度稍微偏离以及为什么标记在椭圆路径中移动。它与世界坐标和窗口坐标有关。或者我的方程式稍微偏离某个地方?
答案 0 :(得分:0)
它看起来像投影问题。在您的拖动代码中,您基本上正在做
lat = a + r cos(baring)
long = b + r sin(baring)
在Lat-Long坐标中给出一个圆圈。如果你在墨卡托投影的赤道上,这将工作正常。随着你进一步走向民意调查,你会得到更多的失真。
假设您使用的是Leaflet reference doc的默认值,您有EPSG3857 Web Mercator坐标。
如果您想确保拥有精确的圆圈,最好使用屏幕坐标。您可以使用ICRS对象上的方法获取这些内容。首先获取坐标系L.CRS.EPSG3857
并使用latLngToPoint
和pointToLatLng
方法。
var crs = L.CRS.EPSG3857;
var zoom = ...; // how you calculate your zoom factor
markerOnRadius.on('drag', function(e){
var markerLL = marker.getLatLng()
var morLL = markerOnRadius.getLatLng();
var markerP = crs.latLngToPoint(markerLL,zoom);
var morP = crs.latLngToPoint(morLL,zoom);
// get the distance between the two points
var dist = markerP.distanceTo(morP);
// Get the vector from center to point
var A = morP.subtract(markerP);
// scale so its of the desired length
var B = A. multiplyBy( factor / dist);
// Add on the center
var C = markerP.add(B);
// Convert back to LatLong
var D = crs.pointToLatLng(C,zoom);
markerOnRadius.setLatLong(D);
});