我正在开发一个应用程序,我有一个圆心和半径,我在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,然后再次开始朝向圆周再次到达圆周时再次完美.
如果你得到它的要点,它就更像椭圆形.
任何人都可以告诉我为什么经度有点偏离以及为什么标记在椭圆形路径中移动.它与世界坐标和窗口坐标有关.或者我的方程式稍微偏离某个地方?
解决方法
它看起来像投影问题.在您的拖动代码中,您基本上是在做
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); });