Как я могу преобразовать geoshape / geotrace / geopoint в GeoJSON?

Я использую API для доступа к пространственным данным, собранным с помощью kobotoolbox. API возвращает пространственные данные в виде geoshape / geotrace / geopoint, но мне нужно скрыть эти данные в Geojson, чтобы я мог отображать их на моей карте с помощью листовки.

вот образец строки геоформы '-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;'

Заранее большое спасибо!

1 ответ

Эта «геоформа» не похожа на какой либо -известный формат векторных данных, а скорее похожа на строку разделенных 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 является из с. Мы можем превратить каждую из этих строк в строку из s, предоставив функцию, которая разбивает ее на пробелы:

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

... и еще одна функция, которая заставляет String содержащий текстовое представление числа в , нравиться...

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

... а теперь давайте в некоторых Array.prototype.map()магия и некоторая магия цепочки методов , чтобы сделать функцию, в которой вход представляет собой строку, разделенную пробелами, а выход представляет собой Array из s:

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

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

Иногда лучше определить те вспомогательные функции, которые передаются (или reduce() или же filter()и т. д.) как анонимные лямбда-функции , например:

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

Давайте изменим это, чтобы добавить еще больше лямбда, цепочки методов и синтаксиса стрелок:

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

Кроме того, поскольку формат GeoJSON ожидает, что каждая координата будет двухкомпонентным вектором, а не четырехкомпонентным вектором, давайте mapкаждый вектор снова, чтобы сохранить только первые два компонента. Здесь используется деструктуризация массива :

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

Видеть? Я определил лямбда-функцию, которая принимает единственный аргумент, предполагает, что это массив (чисел) с длиной 4, разрушает массив, а затем возвращает новый массив, содержащий первые два элемента. Он также может работать как:

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

Ваш образец данных заканчивается ;, и это вызывает пустую строку, поэтому я тоже отфильтрую это:

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

Я предполагаю, что вы работаете в Дар-эс-Саламе, а не в Бадахосе, поэтому давайте поменяем широту и долготу (см. Также https://macwright.com/lonlat/ ), поменяв местами x а также y в ([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);

См. Рабочий пример здесь . И, пожалуйста , не копируйте код вслепую. Прочтите связанную документацию и ресурсы и поймите, что происходит.

Другие вопросы по тегам