从数组中查找国家坐标



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

{
  "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
                ]
              ]
            ]
          }
        }
    ]
}

实际情况是用户将提供latitudelongitude。然后我需要找到这些值是否存在于上面的数据集。如果是,则返回该国家。

问题是上述数据集坐标数组不同。有时是三维的,有时是二维的。它一直在变化。我不知道怎样才能找到有效的解决办法。

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

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函数:它执行地图绘制,鼠标移动处理和显示鼠标移动的国家。但本质在于上面的三个函数。

这是基于本文中介绍的缠绕算法的纯JS,但您可能想要考虑使用库来代替,例如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(即经度,纬度)作为数组传递,并将data对象作为第二个参数:
var country = getCountry([x, y], data);
var countryName = country ? country.properties.name : 'no match';

你的coordinates只是另一个嵌套的坐标数组,在多多边形的情况下,但结构是一样的,所以尝试这样做:

var list = feat;//feat has the json response
list.forEach(function(val, index)
{
  var temp = val.geometry;
  var set = [];
  var type = temp.type.toLowerCase();//just for sake of simplicity
  var coords = [];
  if(type=='polygon')
   coords = temp.coordinates[0];//which is an array of long-lats
  else
  {
    var a = [];
    temp.coordinates.forEach(function(coord)
    {
     a.concat(coord[0]);//note that the 0th index of each array has the list of long-lats
    })
   coords = a;
  }
  temp.coordinates = coords;
});

coordinates key的每个对象现在应该有一个一维数组的lat_long列表。我还没有测试过这个代码,所以请检查一下。您可以测试coordinates的每个索引,以获得一对给定的lat_long。请注意,上面的代码只是简化了您的响应结构,并没有执行实际的搜索。

最新更新