javascript - 从数组中查找国家坐标

标签 javascript arrays node.js

我正在编写一个小应用程序。我有以下数据

{
  "feat": [
        {
          "type": "Feature",
          "id": "AFG",
          "properties": {
            "name": "Afghanistan"
          },
          "geometry": {
            "type": "Polygon",
            "coordinates": [ 
              [
                [
                  61.210817,
                  35.650072
                ],
                [
                  64.546479,
                  36.312073
                ],
                [
                  64.746105,
                  37.111818
                ],
                [
                  65.588948,
                  37.305217
                ],
                [
                  65.745631,
                  37.661164
                ],
                [
                  66.217385,
                  37.39379
                ],
                [
                  66.518607,
                  37.362784
                ],
                [
                  67.075782,
                  37.356144
                ],
                [
                  67.83,
                  37.144994
                ],
                [
                  68.135562,
                  37.023115
                ],
                [
                  68.859446,
                  37.344336
                ],
                [
                  69.196273,
                  37.151144
                ],
                [
                  69.518785,
                  37.608997
                ],
                [
                  70.116578,
                  37.588223
                ],
                [
                  70.270574,
                  37.735165
                ],
                [
                  71.262348,
                  36.074388
                ],
                [
                  71.498768,
                  35.650563
                ],
                [
                  71.613076,
                  35.153203
                ],
                [
                  71.115019,
                  34.733126
                ],
                [
                  71.156773,
                  34.348911
                ],
                [
                  70.881803,
                  33.988856
                ],
                [
                  69.930543,
                  34.02012
                ],
                [
                  70.323594,
                  33.358533
                ],
                [
                  69.687147,
                  33.105499
                ],
                [
                  69.262522,
                  32.501944
                ],
                [
                  69.317764,
                  31.901412
                ],
                [
                  68.926677,
                  31.620189
                ],
                [
                  68.556932,
                  31.71331
                ],
                [
                  67.792689,
                  31.58293
                ],
                [
                  60.52843,
                  33.676446
                ],
                [
                  60.803193,
                  34.404102
                ],
                [
                  61.210817,
                  35.650072
                ]
              ]
            ]
          }
        },
        {
          "type": "Feature",
          "id": "AGO",
          "properties": {
            "name": "Angola"
          },
          "geometry": {
            "type": "MultiPolygon",
            "coordinates": [
              [
                [
                  [
                    16.326528,
                    -5.87747
                  ],
                  [
                    16.57318,
                    -6.622645
                  ],
                  [
                    16.860191,
                    -7.222298
                  ],
                  [
                    17.089996,
                    -7.545689
                  ],
                  [
                    17.47297,
                    -8.068551
                  ],
                  [
                    21.801801,
                    -8.908707
                  ],
                  [
                    21.875182,
                    -9.523708
                  ],
                  [
                    22.208753,
                    -9.894796
                  ],
                  [
                    22.155268,
                    -11.084801
                  ],
                  [
                    22.402798,
                    -10.993075
                  ],
                  [
                    22.837345,
                    -11.017622
                  ],
                  [
                    23.456791,
                    -10.867863
                  ],
                  [
                    23.912215,
                    -10.926826
                  ],
                  [
                    24.017894,
                    -11.237298
                  ],
                  [
                    23.904154,
                    -11.722282
                  ],
                  [
                    24.079905,
                    -12.191297
                  ],
                  [
                    23.930922,
                    -12.565848
                  ],
                  [
                    24.016137,
                    -12.911046
                  ],
                  [
                    21.933886,
                    -12.898437
                  ],
                  [
                    21.887843,
                    -16.08031
                  ],
                  [
                    22.562478,
                    -16.898451
                  ],
                  [
                    23.215048,
                    -17.523116
                  ],
                  [
                    21.377176,
                    -17.930636
                  ],
                  [
                    18.956187,
                    -17.789095
                  ],
                  [
                    18.263309,
                    -17.309951
                  ],
                  [
                    12.175619,
                    -14.449144
                  ],
                  [
                    12.500095,
                    -13.5477
                  ],
                  [
                    12.738479,
                    -13.137906
                  ],
                  [
                    13.312914,
                    -12.48363
                  ],
                  [
                    13.633721,
                    -12.038645
                  ],
                  [
                    13.738728,
                    -11.297863
                  ],
                  [
                    13.686379,
                    -10.731076
                  ],
                  [
                    13.387328,
                    -10.373578
                  ],
                  [
                    13.120988,
                    -9.766897
                  ],
                  [
                    12.87537,
                    -9.166934
                  ],
                  [
                    13.375597,
                    -5.864241
                  ],
                  [
                    16.326528,
                    -5.87747
                  ]
                ]
              ],
              [
                [
                  [
                    12.436688,
                    -5.684304
                  ],
                  [
                    12.182337,
                    -5.789931
                  ]
                ]
              ]
            ]
          }
        },
        {
          "type": "Feature",
          "id": "ALB",
          "properties": {
            "name": "Albania"
          },
          "geometry": {
            "type": "Polygon",
            "coordinates": [
              [
                [
                  20.590247,
                  41.855404
                ],
                [
                  19.406082,
                  40.250773
                ],
                [
                  19.319059,
                  40.72723
                ],
                [
                  19.40355,
                  41.409566
                ],
                [
                  19.540027,
                  41.719986
                ],
                [
                  19.371769,
                  41.877548
                ],
                [
                  19.304486,
                  42.195745
                ],
                [
                  19.738051,
                  42.688247
                ],
                [
                  19.801613,
                  42.500093
                ],
                [
                  20.0707,
                  42.58863
                ],
                [
                  20.283755,
                  42.32026
                ],
                [
                  20.52295,
                  42.21787
                ],
                [
                  20.590247,
                  41.855404
                ]
              ]
            ]
          }
        }
    ]
}

发生的情况是用户将提供纬度经度。然后我需要查找这些值是否存在于上面的数据集中。如果是,则返回该国家/地区。

问题是上面的数据集坐标数组不同。有时是 3 维,有时是 2 维。它在不断变化。我不确定如何找到有效的解决方案。

下面是我的一些代码,目前它提示用户输入纬度和经度并循环数据。

const rl = require('readline').createInterface(process.stdin, process.stdout);
const coordinates = require('./data.json').feat;

var prompts = ['Enter coordinates (lat, lon)'],
    counter = 0;

// console.log(countries);

rl.on('line', (line) => {
    if (!line) {
        console.log('Enter values.');
    }

    let lat = line.split(' ')[0],
        lon = line.split(' ')[1];

    console.log(lat, lon);

    coordinates.forEach((data, index) => {
        console.log(data.geometry.coordinates[index]);
        data.geometry.coordinates.forEach((geo, i) => {
            // console.log(geo[i]);
        });
    });

    get();
}).on('close', () => {

});

function get() {
    rl.setPrompt(prompts[counter] + ': ');
    rl.prompt();
}

get();

在上述数据集中查找给定的经度和纬度有什么帮助吗?

最佳答案

您可以通过检查type属性来检测多边形的数量。如果是 MultiPolygon,您将多一层嵌套级别。

以下是一些可用于确定点是否位于多边形中的函数。代码片段的其余部分(下部)允许测试 getCountry 函数:它执行 map 绘制、鼠标移动处理并显示鼠标移动过的国家/地区。但本质就在最上面的三个函数。

这是普通的 JS,基于 this article 中提供的缠绕算法,但您可能需要考虑使用库来代替,例如 d3.js

function isLeft(p0, p1, p2) {
    return ( (p1[0] - p0[0]) * (p2[1] - p0[1])
           - (p2[0] - p0[0]) * (p1[1] - p0[1]) );
}

function inPoly(p, coord) {
    var winding = 0;
    // loop through all edges of the polygon
    for (var i=0; i<coord.length-1; i++) {
        if (coord[i][1] <= p[1]) {
            if (coord[i+1][1]  > p[1])     // an upward crossing
                 if (isLeft(coord[i], coord[i+1], p) > 0)  // p left of edge
                     ++winding;            // have  a valid up intersect
        } else {                           // start y > P.y (no test needed)
            if (coord[i+1][1] <= p[1])     // a downward crossing
                 if (isLeft(coord[i], coord[i+1], p) < 0)  // p right of  edge
                     --winding;            // have  a valid down intersect
        }
    }
    return winding;
}

function getCountry(p, data) {
    // p: point represented by array with the two coordinates
    var country;
    return data.feat.some(function (obj) {
        country = obj;
        var polygons = obj.geometry.coordinates;
        if (obj.geometry.type !== 'MultiPolygon') polygons = [polygons];
        return polygons.some(function (polygon) {
            return inPoly(p, polygon[0]);
        });
    }) ? country : null;
}

// I/O for this interactive snippet

function drawPolygon(ctx, coord, fillColor) {
    ctx.fillStyle = fillColor;
    ctx.beginPath();
    coord.forEach(function (point, i) {
        if (i==0) {
            ctx.moveTo(point[0], point[1]);
        } else {
            ctx.lineTo(point[0], point[1]);
        }
    });
    ctx.fill();
    ctx.stroke();
//    ctx.closePath();
}

function drawCountry(ctx, selectedCountry, country) {
    var polygons = country.geometry.coordinates;
    var color = selectedCountry == country ? 'yellow' : 'grey';
    if (country.geometry.type !== 'MultiPolygon') polygons = [polygons];
    polygons.forEach(function (polygon) {
        drawPolygon(ctx, polygon[0], color);
    });
}

function drawWorld(ctx, data, selectedCountry) {
    data.feat.forEach(drawCountry.bind(null, ctx, selectedCountry));
}

// Define transformation so countries will be mapped to canvas area
var scale = [3, -3];
var move = [-20, 130];

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext("2d");
ctx.translate(...move);
ctx.scale(...scale);
ctx.lineWidth = 1/scale[0];

// Sample data
var data = {"feat":[{"type":"Feature","id":"AFG","properties":{"name":"Afghanistan"},"geometry":{"type":"Polygon","coordinates":[[[61.210817,35.650072],[62.230651,35.270664],[62.984662,35.404041],[63.193538,35.857166],[63.982896,36.007957],[64.546479,36.312073],[64.746105,37.111818],[65.588948,37.305217],[65.745631,37.661164],[66.217385,37.39379],[66.518607,37.362784],[67.075782,37.356144],[67.83,37.144994],[68.135562,37.023115],[68.859446,37.344336],[69.196273,37.151144],[69.518785,37.608997],[70.116578,37.588223],[70.270574,37.735165],[70.376304,38.138396],[70.806821,38.486282],[71.348131,38.258905],[71.239404,37.953265],[71.541918,37.905774],[71.448693,37.065645],[71.844638,36.738171],[72.193041,36.948288],[72.63689,37.047558],[73.260056,37.495257],[73.948696,37.421566],[74.980002,37.41999],[75.158028,37.133031],[74.575893,37.020841],[74.067552,36.836176],[72.920025,36.720007],[71.846292,36.509942],[71.262348,36.074388],[71.498768,35.650563],[71.613076,35.153203],[71.115019,34.733126],[71.156773,34.348911],[70.881803,33.988856],[69.930543,34.02012],[70.323594,33.358533],[69.687147,33.105499],[69.262522,32.501944],[69.317764,31.901412],[68.926677,31.620189],[68.556932,31.71331],[67.792689,31.58293],[67.683394,31.303154],[66.938891,31.304911],[66.381458,30.738899],[66.346473,29.887943],[65.046862,29.472181],[64.350419,29.560031],[64.148002,29.340819],[63.550261,29.468331],[62.549857,29.318572],[60.874248,29.829239],[61.781222,30.73585],[61.699314,31.379506],[60.941945,31.548075],[60.863655,32.18292],[60.536078,32.981269],[60.9637,33.528832],[60.52843,33.676446],[60.803193,34.404102],[61.210817,35.650072]]]}},{"type":"Feature","id":"AGO","properties":{"name":"Angola"},"geometry":{"type":"MultiPolygon","coordinates":[[[[16.326528,-5.87747],[16.57318,-6.622645],[16.860191,-7.222298],[17.089996,-7.545689],[17.47297,-8.068551],[18.134222,-7.987678],[18.464176,-7.847014],[19.016752,-7.988246],[19.166613,-7.738184],[19.417502,-7.155429],[20.037723,-7.116361],[20.091622,-6.94309],[20.601823,-6.939318],[20.514748,-7.299606],[21.728111,-7.290872],[21.746456,-7.920085],[21.949131,-8.305901],[21.801801,-8.908707],[21.875182,-9.523708],[22.208753,-9.894796],[22.155268,-11.084801],[22.402798,-10.993075],[22.837345,-11.017622],[23.456791,-10.867863],[23.912215,-10.926826],[24.017894,-11.237298],[23.904154,-11.722282],[24.079905,-12.191297],[23.930922,-12.565848],[24.016137,-12.911046],[21.933886,-12.898437],[21.887843,-16.08031],[22.562478,-16.898451],[23.215048,-17.523116],[21.377176,-17.930636],[18.956187,-17.789095],[18.263309,-17.309951],[14.209707,-17.353101],[14.058501,-17.423381],[13.462362,-16.971212],[12.814081,-16.941343],[12.215461,-17.111668],[11.734199,-17.301889],[11.640096,-16.673142],[11.778537,-15.793816],[12.123581,-14.878316],[12.175619,-14.449144],[12.500095,-13.5477],[12.738479,-13.137906],[13.312914,-12.48363],[13.633721,-12.038645],[13.738728,-11.297863],[13.686379,-10.731076],[13.387328,-10.373578],[13.120988,-9.766897],[12.87537,-9.166934],[12.929061,-8.959091],[13.236433,-8.562629],[12.93304,-7.596539],[12.728298,-6.927122],[12.227347,-6.294448],[12.322432,-6.100092],[12.735171,-5.965682],[13.024869,-5.984389],[13.375597,-5.864241],[16.326528,-5.87747]]],[[[12.436688,-5.684304],[12.182337,-5.789931],[11.914963,-5.037987],[12.318608,-4.60623],[12.62076,-4.438023],[12.995517,-4.781103],[12.631612,-4.991271],[12.468004,-5.248362],[12.436688,-5.684304]]]]}},{"type":"Feature","id":"ALB","properties":{"name":"Albania"},"geometry":{"type":"Polygon","coordinates":[[[20.590247,41.855404],[20.463175,41.515089],[20.605182,41.086226],[21.02004,40.842727],[20.99999,40.580004],[20.674997,40.435],[20.615,40.110007],[20.150016,39.624998],[19.98,39.694993],[19.960002,39.915006],[19.406082,40.250773],[19.319059,40.72723],[19.40355,41.409566],[19.540027,41.719986],[19.371769,41.877548],[19.304486,42.195745],[19.738051,42.688247],[19.801613,42.500093],[20.0707,42.58863],[20.283755,42.32026],[20.52295,42.21787],[20.590247,41.855404]]]}}]};
// Show map on canvas
window.onload = drawWorld.bind(null, ctx, data, null);

// Handle mouse move to mention the matching country
canvas.onmousemove = function (e) {
    // Get mouse coordinates relative to canvas
    var x = e.pageX - this.offsetLeft;
    var y = e.pageY - this.offsetTop;
    // Perform the reverse of the canvas transformation
    x = (x - move[0]) / scale[0];
    y = (y - move[1]) / scale[1];
    // Get country that contains this point
    var country = getCountry([x, y], data);
    var countryName = country ? country.properties.name : 'no match';
    // Output the result
    document.getElementById('country').textContent = countryName;
    // Highight country
    drawWorld(ctx, data, country)
};
canvas { border:1px solid; float: left }
<canvas width="250", height="200"></canvas>
<div id="country">Hover mouse...</div>

有关性能的说明

当数据集中有大量多边形列表时,检查每个多边形的每条边以确定点的适合位置确实是浪费时间。

如果您对数据进行预处理并向每个多边形添加框信息,这将是一个重大改进:完全包围多边形的正方形 ([minx,miny]-[maxx,maxy]) 。当你需要匹配一个点时,你会首先匹配这个盒子,如果它在外面,你可以跳过那个多边形,节省时间。通常只有几个盒子包含您的点,因此您只需要针对这几个多边形进行测试。

要获取国家/地区名称:

像上面的代码片段中那样调用 getCountry 函数,其中传递用户定义的 xy (即经度、 latitude) 作为数组,data 对象作为第二个参数:

var country = getCountry([x, y], data);
var countryName = country ? country.properties.name : 'no match';

关于javascript - 从数组中查找国家坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39315190/

相关文章:

javascript - 使用 JavaScript 在 HTML Canvas 上绘制螺旋

javascript - 如何在重新填充 jsTree 后触发它的选择节点事件

javascript - 检查哈希数组是否包含哈希

javascript - 带有选项、回调和错误处理器的 Node.js fs.writeFileSync?

javascript - 查找包含不包含特定值的数组的文档

javascript - 谷歌图书 API : Cannot read property 'thumbnail' of undefined

javascript - 不隐藏其他内容的jquery淡入淡出效果

javascript - 根据较高的内部值比较数组

arrays - 在 Julia 中将 Vector 转换为 Matrix 的最佳方法?

node.js - 多个node.js程序同时运行