Calculate the mid point of latitude and longitude co-ordinates

后端 未结 4 1506
我寻月下人不归
我寻月下人不归 2021-01-13 12:41

Does anyone know the best way to go about getting the mid-point of a pair of latitude and longitude points?

I mm using d3.js to draw points on a map and need to draw

相关标签:
4条回答
  • 2021-01-13 12:44

    I always use geo-lib and works

    0 讨论(0)
  • 2021-01-13 12:49

    Apologies for the long script - it just seemed fun to draw stuff :-). I've marked off sections that are not required

    // 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);
    

    Fiddle - https://jsfiddle.net/srjuc2gd/


    enter image description here


    And here's just the relevant portion (most of it is just copy-pasta from the beginning of this answer)

    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]);
    
    0 讨论(0)
  • 2021-01-13 12:57

    Check this question, you can use it to find the middle of your coordination on google map. I customized it to use with d3js. Hope this help you.

    In D3

    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;
    };
    

    Update 1

    If you try to draw curve line, you should create a path with coordination such as :

    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");
    

    You need to create your curve line as you want in d3. JsFiddle here.

    0 讨论(0)
  • 2021-01-13 13:01

    For the accurate side:

    You may use the Esri web API. Nothing beats decades of experience implementing the hard side of projection systems and datums... Athough the ArcGIS for Server line is a commercial product, the JS API is free, and here there's a pure JS function that does just what you want : geometryEngine.densify ; that function requires an interval parameter, that you can, in your case, get by dividing by two the results of geometryEngine.geodesicLength

    That'll need you to get acquainted with the Polyline class in a very basic way, such as var mySegment = new Polyline([[50,3], [55,8]]); and probably nothing further.

    For the visual side :

    Your segment has two middles ? You may also be interested in geometryEngine.offset ; first offset the original segment once in each direction, then get the center point for each of the resulting segments.

    For the practical side :

    Given the short distances involved, provided you're not dealing with a weird place that'd be too close to the poles, I'd simply go with an arithmetic average of X and Y, and then add/subtract a rotated vector to offset your two "middles". Doing it this way would be both lighter on the machine (no libs to load from a CDN), easier on you, and as long as the purpose of it is a nice display, the result will be more than good enough.

    (added as per comment : a sample)

    // 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};
    
    0 讨论(0)
提交回复
热议问题