计算经纬度坐标的中点

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 和作品

【讨论】:

以上是关于计算经纬度坐标的中点的主要内容,如果未能解决你的问题,请参考以下文章

两个坐标列表的欧几里得距离矩阵

IOS 通过经纬度计算两点的距离及坐标系转换

怎么算经纬度和距离呢?

sql怎么将一系列点经纬度坐标匹配到某市

坐标转换经纬度

利用SQL计算两个地理坐标(经纬度)之间的地表距离