计算经纬度坐标的中点
Posted
技术标签:
【中文标题】计算经纬度坐标的中点【英文标题】:Calculate the mid point of latitude and longitude co-ordinates 【发布时间】:2015-10-04 08:28:09 【问题描述】:有谁知道获得一对纬度和经度点中点的最佳方法?
我mm使用d3.js在地图上画点,需要在两点之间画一条曲线,所以我需要创建一个中点来画一条曲线。
请参阅下图以更好地了解我正在尝试做的事情:
【问题讨论】:
您有技术问题吗?还是您只是想在数学方面得到帮助? @ColBeseder 我将不胜感激数学方面的一些帮助。我绘制线条等没有问题,提供的图像是一个工作示例,但我必须对中点进行硬编码,因为我必须绘制更多,所以不可扩展。 【参考方案1】:为冗长的脚本道歉 - 画东西看起来很有趣 :-)。我已经标记了不需要的部分
// your latitude / longitude
var co2 = [70, 48];
var co1 = [-70, -28];
// NOT REQUIRED
var ctx = document.getElementById("myChart").getContext("2d");
function drawPoint(color, point)
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(point.x, point.y, 5, 0, 2 * Math.PI, false);
ctx.fill();
function drawCircle(point, r)
ctx.strokeStyle = 'gray';
ctx.setLineDash([5, 5]);
ctx.beginPath();
ctx.arc(point.x, point.y, r, 0, 2 * Math.PI, false);
ctx.stroke();
// REQUIRED
// convert to cartesian
var projection = d3.geo.equirectangular()
var cot1 = projection(co1);
var cot2 = projection(co2);
var p0 = x: cot1[0], y: cot1[1] ;
var p1 = x: cot2[0], y: cot2[1] ;
// NOT REQUIRED
drawPoint('green', p0);
drawPoint('green', p1);
// REQUIRED
function dfn(p0, p1)
return Math.pow(Math.pow(p0.x - p1.x, 2) + Math.pow(p0.y - p1.y, 2), 0.5);
// from http://math.stackexchange.com/a/87374
var d = dfn(p0, p1);
var m =
x: (p0.x + p1.x) / 2,
y: (p0.y + p1.y) / 2,
var u = (p1.x - p0.x) / d
var v = (p1.y - p0.y) / d;
// increase 1, if you want a larger curvature
var r = d * 1;
var h = Math.pow(Math.pow(r, 2) - Math.pow(d, 2) / 4, 0.5);
// 2 possible centers
var c1 =
x: m.x - h * v,
y: m.y + h * u
var c2 =
x: m.x + h * v,
y: m.y - h * u
// NOT REQUIRED
drawPoint('gray', c1)
drawPoint('gray', c2)
drawCircle(c1, r)
drawCircle(c2, r)
// REQUIRED
// from http://math.stackexchange.com/a/919423
function mfn(p0, p1, c)
// the -c1 is for moving the center to 0 and back again
var mt1 =
x: r * (p0.x + p1.x - c.x * 2) / Math.pow(Math.pow(p0.x + p1.x - c.x * 2, 2) + Math.pow(p0.y + p1.y - c.y * 2, 2), 0.5)
;
mt1.y = (p0.y + p1.y - c.y * 2) / (p0.x + p1.x - c.x * 2) * mt1.x;
var ma =
x: mt1.x + c.x,
y: mt1.y + c.y,
var mb =
x: -mt1.x + c.x,
y: -mt1.y + c.y,
return (dfn(ma, p0) < dfn(mb, p0)) ? ma : mb;
var m1 = mfn(p0, p1, c1);
var m2 = mfn(p0, p1, c2);
var mo1 = projection.invert([m1.x, m1.y]);
var mo2 = projection.invert([m2.x, m2.y]);
// NOT REQUIRED
drawPoint('blue', m1);
drawPoint('blue', m2);
// your final output (in lat long)
console.log(mo1);
console.log(mo2);
小提琴 - https://jsfiddle.net/srjuc2gd/
这只是相关部分(大部分只是从这个答案的开头复制意大利面)
var Q31428016 = (function ()
// adjust curvature
var CURVATURE = 1;
// project to convert from lat / long to cartesian
var projection = d3.geo.equirectangular();
// distance between p0 and p1
function dfn(p0, p1)
return Math.pow(Math.pow(p0.x - p1.x, 2) + Math.pow(p0.y - p1.y, 2), 0.5);
// mid point between p0 and p1
function cfn(p0, p1)
return
x: (p0.x + p1.x) / 2,
y: (p0.y + p1.y) / 2,
// get arc midpoint given end points, center and radius - http://math.stackexchange.com/a/919423
function mfn(p0, p1, c, r)
var m = cfn(p0, p1);
// the -c1 is for moving the center to 0 and back again
var mt1 =
x: r * (m.x - c.x) / Math.pow(Math.pow(m.x - c.x, 2) + Math.pow(m.y - c.y, 2), 0.5)
;
mt1.y = (m.y - c.y) / (m.x - c.x) * mt1.x;
var ma =
x: mt1.x + c.x,
y: mt1.y + c.y,
var mb =
x: -mt1.x + c.x,
y: -mt1.y + c.y,
return (dfn(ma, p0) < dfn(mb, p0)) ? ma : mb;
var Q31428016 = ;
Q31428016.convert = function (co1, co2)
// convert to cartesian
var cot1 = projection(co1);
var cot2 = projection(co2);
var p0 = x: cot1[0], y: cot1[1] ;
var p1 = x: cot2[0], y: cot2[1] ;
// get center - http://math.stackexchange.com/a/87374
var d = dfn(p0, p1);
var m = cfn(p0, p1);
var u = (p1.x - p0.x) / d
var v = (p1.y - p0.y) / d;
var r = d * CURVATURE;
var h = Math.pow(Math.pow(r, 2) - Math.pow(d, 2) / 4, 0.5);
// 2 possible centers
var c1 =
x: m.x - h * v,
y: m.y + h * u
var c2 =
x: m.x + h * v,
y: m.y - h * u
// get arc midpoints
var m1 = mfn(p0, p1, c1, r);
var m2 = mfn(p0, p1, c2, r);
// convert back to lat / long
var mo1 = projection.invert([m1.x, m1.y]);
var mo2 = projection.invert([m2.x, m2.y]);
return [mo1, mo2]
return Q31428016;
)();
// your latitude / longitude
var co1 = [-70, -28];
var co2 = [70, 48];
var mo = Q31428016.convert(co1, co2)
// your output
console.log(mo[0]);
console.log(mo[1]);
【讨论】:
谢谢,我将仔细阅读提供的所有答案,以确保为我的案例选择最好的答案。不过,这看起来很有趣。您能否为遇到此问题的其他人提供仅包含相关部分的较小代码库? 抱歉,我忘了问您是否可以为遇到此答案的任何其他用户创建一个工作 + 可编辑示例(codepen/jsfiddle 等)。添加此项将使您更有可能成为被选中的人,因为它允许新访问者使用您的实现。 答案中间有一个 Show Code sn-p。那个工作?顺便说一句,这是一个小提琴 - jsfiddle.net/srjuc2gd。我不想让答案膨胀:-),但如果您觉得它会改善答案,请随时编辑它。干杯! 用户无法编辑“显示片段”部分。太好了,您现在也可以提示您回答。很好的回答。谢谢 感谢您的回答。对于需要绘制来自多个不同点的多条线的情况,我该如何更改?例如,假设我添加的图像中没有 2 个圆圈,而是 10 个,我想在它们之间画线?【参考方案2】:准确的一面:
您可以使用 Esri Web API。没有什么比几十年来实现投影系统和基准面的经验更胜一筹了……尽管 ArcGIS for Server 系列是商业产品,但 JS API 是免费的,这里有一个纯 JS 函数可以满足您的需求:@987654321 @;该函数需要一个间隔参数,在您的情况下,您可以通过将geometryEngine.geodesicLength的结果除以二来获得该参数
这需要您以非常基本的方式熟悉Polyline 类,例如var mySegment = new Polyline([[50,3], [55,8]]);
,可能不会再进一步了。
视觉方面:
你的部分有两个中间?您可能还对geometryEngine.offset 感兴趣;首先将原始线段在每个方向上偏移一次,然后获取每个结果线段的中心点。
实用方面:
考虑到所涉及的短距离,只要您不是在处理离两极太近的奇怪地方,我只需使用 X 和 Y 的算术平均值,然后添加/减去旋转的向量来抵消你的两个“中间”。这样做在机器上会更轻(无需从 CDN 加载库),对你来说更容易,而且只要它的目的是一个漂亮的显示,结果就会足够好。
(根据评论添加:示例)
// Your known starting points, and a k factor of your choice.
var a = x:3, y:50;
var b = x:8, y:55;
var k = 0.2;
// Intermediate values
var vab = x:b.x-a.x, y:b.y-a.y;
var v_rotated = x:-k*vab.y, y:k*vab.x;
var middle = x:a.x+vab.x/2, y:a.y+vab.y/2;
// Your two resulting points
var result_i = x: middle.x + v_rotated.x, y: middle.y + v_rotated.y;
var result_j = x: middle.x - v_rotated.x, y: middle.y - v_rotated.y;
【讨论】:
你有没有实用方面的sn-pt代码:? 当然。这只是您的基本向量数学,由于 Javacript 缺少向量运算符而有些混淆。 :) 我坚持认为这不会产生 geographically 合理的点,因此使用 x 和 y 而不是 lon 和 lat,但是它在城市/县地图上应该看起来不错,而不是在英国地图上令人震惊。 谢谢,让我浏览一下答案,然后选择最适合我的情况的答案。我可能最终会投票很多答案,因为有很多很棒的答案。 SO社区> 我猜原因是,在我们在这里看到的经常出现的 JS 问题的范围内,您的问题的标题有望带来令人耳目一新的变化。 :D 是的,你可能是对的。很多人倾向于在不检查答案是否已经存在的情况下提出问题。我在发帖前确实环顾四周。像你这样的人对回答一个相对不被问到的问题感到兴奋是件好事。谢谢【参考方案3】:检查this问题,你可以用它在谷歌地图上找到你的协调中心。我将它定制为与 d3js 一起使用。 希望对您有所帮助。
在第三天
function midpoint (lat1, lng1, lat2, lng2)
lat1= deg2rad(lat1);
lng1= deg2rad(lng1);
lat2= deg2rad(lat2);
lng2= deg2rad(lng2);
dlng = lng2 - lng1;
Bx = Math.cos(lat2) * Math.cos(dlng);
By = Math.cos(lat2) * Math.sin(dlng);
lat3 = Math.atan2( Math.sin(lat1)+Math.sin(lat2),
Math.sqrt((Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx) + By*By ));
lng3 = lng1 + Math.atan2(By, (Math.cos(lat1) + Bx));
return (lat3*180)/Math.PI .' '. (lng3*180)/Math.PI;
function deg2rad (degrees)
return degrees * Math.PI / 180;
;
更新 1
如果你尝试绘制曲线,你应该创建一个协调的路径,例如:
var lat1=53.507651,lng1=10.046997,lat2=52.234528,lng2=10.695190;
var svg=d3.select("body").append("svg").attr(width:700 , height:600);
svg.append("path").attr("d", function (d)
var dC="M "+lat1+","+lng1+ " A " + midpoint (lat1, lng1, lat2, lng2)
+ " 0 1,0 " +lat2 +" , "+lng2 +"Z";
return dC;
)
.style("fill","none").style("stroke" ,"steelblue");
您需要在 d3 中根据需要创建曲线。 JsFiddle here.
【讨论】:
谢谢。这会导致轻微的曲线还是只是画一条直线? 我更新了我的答案以绘制曲线,但我认为@potatopeelings 的答案非常酷。 谢谢,您是否对此进行了测试以确保它绘制出曲线?你有一个工作示例(小提琴、codepen 等)吗?感谢所有的帮助和很好的回答 我更新了我的答案并添加了 jsfiddle 链接。抱歉,我无法将任何地图加载到 jsfiddle,但坐标是从谷歌地图获取的。【参考方案4】:我总是使用geo-lib 和作品
【讨论】:
以上是关于计算经纬度坐标的中点的主要内容,如果未能解决你的问题,请参考以下文章