0

我正在使用 API 访问使用 kobotoolbox 收集的空间数据。api以geoshape/geotrace/geopoint的形式返回空间数据,但我需要将该数据转换为Geojson,以便我可以使用传单将它们显示在我的地图上。

这是geoshape的示例字符串'-6.725577650887138 39.10606026649475 0.0 0.0;-6.72631550943841 39.10506717860699 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.725577650887138 39.10606026649475 0.0 0.0;'

提前非常感谢!

4

1 回答 1

1

该“geoshape”看起来不像任何众所周知的矢量数据格式,而是看起来像一串- 分隔的;4 元素向量,而这些向量又是空格分隔的数字。

一些天真的解析是有序的。

首先将字符串拆分为字符串数组String.prototype.split()

let geoshape = '-6.725577650887138 39.10606026649475 0.0 0.0;-6.72631550943841 39.10506717860699 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.725577650887138 39.10606026649475 0.0 0.0;';

let points = geoshape.split(';');

现在points是sArray的一个String。我们可以通过提供一个用空格分隔字符串的函数将这些字符串中的每一个转换为一个Arrayof s:Number

function spaceSeparatedStringToArray(str) {
     return str.split(' ');
}

String...以及将包含数字文本表示的 a强制转换为 a 的另一个函数Number,例如...

function stringToNumber(str) {
    return Number(str);
}

...现在让我们加入一些Array.prototype.map()魔法和一些方法链接魔法,来创建一个函数,其中输入是一个空格分隔的字符串,输出是一个Arrays Number

function stringToNumber(str) { return Number(str); }

function spaceSeparatedStringToArrayOfNumbers(str) {
    return str.split(' ').map(stringToNumber);
}

有时将传递给map()(或reduce()filter()或等)的那些辅助函数定义为匿名 lambda-functions会更好,例如:

function spaceSeparatedStringToArrayOfNumbers(str) {
    return str.split(' ').map(function(str){ return Number(str) });
}

如果需要,您可以使用箭头函数语法

function spaceSeparatedStringToArrayOfNumbers(str) {
    return str.split(' ').map(str=>Number(str) );
}

由于我们使用Number的是函数,我们可以直接使用它作为参数map()

function spaceSeparatedStringToArrayOfNumbers(str) {
    return str.split(' ').map(Number);
}

现在我们有了这个函数,让我们回到开头,将该函数应用于每个 - 分隔的;子字符串:

function spaceSeparatedStringToArrayOfNumbers(str) {
    return str.split(' ').map(Number);
}

let geoshape = '-6.725577650887138 39.10606026649475 0.0 0.0;-6.72631550943841 39.10506717860699 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.725577650887138 39.10606026649475 0.0 0.0;';

let points = geoshape.split(';');

let vectors = points.map(spaceSeparatedStringToArrayOfNumbers);

让我们更改它以添加更多 lambda 和方法链接以及箭头语法:

let vectors = geoshape.split(';').map((str)=>str.split(' ').map(Number));

此外,由于 GeoJSON 格式期望每个坐标为 2 分量向量而不是 4 分量向量,因此让我们map再次对每个向量进行处理,以仅保留前两个分量。这使用数组解构

let vectors = geoshape
               .split(';')
               .map((str)=>str.split(' ').map(Number))
               .map(([x,y,w,z])=>[x,y]);

看?我定义了一个 lambda 函数,它接受一个参数,假设它是一个长度为 4 的数组(数字),解构数组,然后返回一个包含前两个元素的新数组。它也可以像这样工作:

let coords = geoshape
               .split(';')
               .map((str)=>str.split(' ').map(Number))
               .map(([x,y])=>[x,y]);

您的示例数据以 a 结尾;,这会导致一个空字符串,因此我也会将其过滤掉:

let coords = geoshape
               .split(';')
               .filter(str=> str!=='')
               .map((str)=>str.split(' ').map(Number))
               .map(([x,y])=>[x,y]);

我假设您在达累斯萨拉姆工作,而不是在巴达霍斯工作,所以让我们通过交换和in来翻转纬度和经度(参见https://macwright.com/lonlat/ ) :xy([x,y])=>[y,x]

let coords = geoshape
               .split(';')
               .filter(str=> str!=='')
               .map((str)=>str.split(' ').map(Number))
               .map(([x,y])=>[y,x]);

现在前往geojson.org并阅读RFC 7946以了解如何指定 GeoJSON 数据结构。我们已经有了 LineString 几何的坐标,所以它只需要一些包装:

let geojsonFeature = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "LineString",
    "coordinates": coords
  }
};

如果您的示例数据集是一个带有外壳而没有内壳的多边形(阅读OGC SFA以了解“外壳”在此上下文中的含义),那么您可以将坐标包装在一个额外的内联数组中并指定Polygon为几何类型:

let geojsonFeature = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [ coords ]
  }
};

现在你可以把它喂给L.geoJson,例如

let line = L.geoJson(geojsonFeature).addTo(map);

最后,为了它,我要把所有东西都压缩在一起:

let geoshape = '-6.725577650887138 39.10606026649475 0.0 0.0;-6.72631550943841 39.10506717860699 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.727484560110362 39.10561669617891 0.0 0.0;-6.725577650887138 39.10606026649475 0.0 0.0;';

let leafletLine = L.geoJson({
    "type": "Feature",
    "properties": {},
    "geometry": {
        "type": "LineString",
        "coordinates": geoshape
                   .split(';')
                   .filter(str=> str!=='')
                   .map((str)=>str.split(' ').map(Number))
                   .map(([x,y])=>[y,x])
    }
}).addTo(map);

在此处查看一个工作示例。请不要盲目地复制粘贴代码请阅读链接的文档和资源,并了解发生了什么。

于 2021-04-14T16:04:01.713 回答