我正在写一个小应用程序。我有以下数据
{
"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
]
]
]
}
}
]
}
用户将提供latitude
和longitude
。然后我需要找出上述数据集中是否存在这些值。如果它然后返回该国家。
问题是上面的数据集坐标数组是不同的。有时它是三维的,有时它是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();
在上述数据集中查找给定经度和纬度的任何帮助?
答案 0 :(得分:2)
您可以通过检查type
属性来检测多边形的数量。如果是MultiPolygon
,则您还会有一个嵌套级别。
以下是一些可用于确定点是否在多边形中的函数。片段的其余部分(下半部分)允许测试getCountry
功能:它执行地图绘制,鼠标移动处理并显示鼠标移动的国家/地区。但实质是在顶部的三个功能。
这是简单的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)
};
&#13;
canvas { border:1px solid; float: left }
&#13;
<canvas width="250", height="200"></canvas>
<div id="country">Hover mouse...</div>
&#13;
如果数据集中有多个多边形列表,那么检查每个多边形的每个边缘以确定该点适合的位置实际上是浪费时间。
如果您要预处理数据并向每个多边形添加框信息,这将是一项重大改进:一个完全包含多边形的正方形([minx,miny]-[maxx,maxy]
)。当您需要匹配一个点时,您将首先匹配此框,如果它在外面,您可以跳过该多边形,从而节省花费在其上的时间。通常只会有一些包含你的观点的盒子,所以你只需要测试那些少数多边形。
调用getCountry
函数,就像在上面的代码段中一样,您将用户定义的x
和y
(即经度,纬度)作为数组传递,并且{ {1}} object作为第二个参数:
data
答案 1 :(得分:0)
对于multiploygon,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
键现在应该有一个lat-long列表的一维数组。我还没有测试过这段代码,所以请检查一下。对于给定的lat-long对,您可以测试coordinates
的每个索引。请注意,上述代码只是简化了您的响应结构,并且不执行实际搜索。