Проверьте geojson перед созданием Mapbox MGLShape - PullRequest
0 голосов
/ 17 февраля 2019

Я использую iOS Mapbox SDK для создания MGLShapeCollectionFeature из данных goejson FeatureCollection, которые поступают из стороннего API.

guard let feature = try? MGLShape(data: jsonData, encoding: String.Encoding.utf8.rawValue) as? MGLShapeCollectionFeature else {
    print("Could not cast to specified MGLShapeCollectionFeature")
    return
}

Проблема заключается в том, что API иногда возвращает недопустимый геойсон, где одиночный Feature не содержит действительных координат (см. Ниже), и инициализация MGLShape завершается с помощью 'NSInvalidArgumentException', reason: 'A multipoint must have at least one vertex.', что является правильным.

Есть ли способ отфильтровать и удалить недействительные Features внутри FeatureCollection, отличные от парсинга и исправления геоджона вручную?

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "icaoId": "KBOS",
        "airSigmetType": "AIRMET",
        "hazard": "IFR"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [

          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "icaoId": "KSLC",
        "airSigmetType": "AIRMET",
        "hazard": "IFR"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -106.63,
              49.06
            ],
            [
              -104.12,
              48.95
            ],
            [
              -104.17,
              44.8
            ],
            [
              -106.91,
              46.38
            ],
            [
              -106.63,
              49.06
            ]
          ]
        ]
      }
    }
  ]
}

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

Как вы и предлагали, я сам сделал фильтрацию и написал это расширение на Data

extension Data {

    func removeEmptyCoordinates() throws -> Data {
        guard var geojson = try JSONSerialization.jsonObject(with: self, options: []) as? [String: Any] else {
            return self
        }
        fix(geojson: &geojson,
            processFeatureIf: NSPredicate(format: "geometry.type == 'Polygon'"),
            keepFeatureIf: NSPredicate(format: "%K[0][SIZE] >= 2", "geometry.coordinates"))
        return try JSONSerialization.data(withJSONObject: geojson, options: [])
    }

    private func fix(geojson: inout [String: Any], processFeatureIf: NSPredicate, keepFeatureIf: NSPredicate) {
        guard let type = geojson["type"] as? String, type == "FeatureCollection" else {
            // "Not a FeatureCollection"
            return
        }
        // "No features to fix"
        guard let features = geojson["features"] as? [[String: Any]] else { return }

        let filtered = features.filter { feature in
            if !processFeatureIf.evaluate(with: feature) {
                // not processing
                return true
            }
            return keepFeatureIf.evaluate(with: feature)
        }
        geojson["features"] = filtered
    }
}
0 голосов
/ 17 февраля 2019

Возможное решение - декодировать JSON с Codable в структуры, фильтровать пустые элементы и кодировать объект обратно:

struct FeatureCollection : Codable {
    let type : String
    var features : [Feature]
}

struct Feature : Codable {
    let type : String
    let properties : Properties
    let geometry : Geometry
}

struct Properties : Codable {
    let icaoId, airSigmetType, hazard : String
}

struct Geometry : Codable {
    let type : String
    let coordinates : [[[Double]]]
}

do {
    var result = try JSONDecoder().decode(FeatureCollection.self, from: jsonData)
    let filteredFeatures = result.features.filter{$0.geometry.coordinates != [[]]}
    result.features = filteredFeatures
    let filteredData = try JSONEncoder().encode(result)
    guard let feature = try? MGLShape(data: filteredData, encoding: String.Encoding.utf8.rawValue) as? MGLShapeCollectionFeature else {
        print("Could not cast to specified MGLShapeCollectionFeature")
        return
    }
} catch {
    print(error)
}
...