1

I'm using MapBox (Turf), trying to filter a specific Feature from a FeatureCollection. I successfully export the GeoJSON from QGIS and decode the GeoJSON into a FeatureCollection. I can't figure out the syntax to access the geometry (multiPolygon).

The FeatureCollection object looks like this:

[Turf.Feature(identifier: nil, properties: Optional(["place": Optional(Turf.JSONValue.string("Anytown, PA")), "name": Optional(Turf.JSONValue.string("Neighborhood")), "type": Optional(Turf.JSONValue.string("origin-zone")), "srno": Optional(Turf.JSONValue.number(31.0))]), geometry: Optional(Turf.Geometry.multiPolygon(Turf.MultiPolygon(coordinates: [[[__C.CLLocationCoordinate2D(latitude: 40.4435110405471, longitude: -79.93806054350729),...

This is as close as I've been able to get:

let features = serviceAreaPolygon.features.filter{$0.geometry.multiPolygon(MultiPolygon)}

which throws an error "Cannot convert value of type 'MultiPolygon.Type' to expected argument type 'MultiPolygon'"

Here is the structure:

public struct FeatureCollection: Equatable, ForeignMemberContainer {
    /// The features that the collection contains.
    public var features: [Feature] = []
public struct Feature: Equatable, ForeignMemberContainer {

    public var identifier: FeatureIdentifier?
    public var properties: JSONObject?
    public var geometry: Geometry?

    public init(geometry: Geometry) {
        self.geometry = geometry
    }
public enum Geometry: Equatable {
    case multiPolygon(_ geometry: MultiPolygon)
}
extension Geometry: Codable {
    private enum CodingKeys: String, CodingKey {
        case kind = "type"
    }
    
    enum Kind: String, Codable, CaseIterable {
        ...
        case MultiPolygon
    }

extension MultiPolygon: GeometryConvertible {
    public var geometry: Geometry { return .multiPolygon(self) }
}

This is probably very simple, but I've been fighting this for about 4 hours...

Thanks in advance.

Jeff Ericson
  • 61
  • 1
  • 9
  • 2
    I don't know the types you are working with here but I do know that the `filter` closure should return a Bool which yours clearly don't. As for the error, you are passing in a type where an object is expected so you need to pass an instance of MultiPolygon – Joakim Danielson Feb 20 '22 at 21:46

1 Answers1

2

Assuming you've decoded the FeatureCollection and would now like to access the MultiPolygon property of select features in an array of Features, then you should write something like:

//FeaturesArray
let featuresCollection = serviceAreaPolygon.features
//Filtering for only Features with Multipolygons
let featuresWithgMultiPolygons = featuresCollection.filter{$0.geometry.type == "MultiPolygon"}

(I am not familiar with the exact structure of your data, but I am using this documentation on the GeoJSON standard, a MultiPolygon is found in the Feature object)

I think you are over engineering your solution to what appears to be a relatively simple problem.

The Swift Coder
  • 390
  • 3
  • 13
  • Thanks. The structs are straight from the Turf SDK (part of MapBox). I started not too far from what you put, but it tells me 'Geometry' doesn't have a member 'type.' Per the bottom code block I copied in, Geometry is an enum with a 'kind' case that = "type" but I haven't figured out how to translate that into the expression. – Jeff Ericson Feb 20 '22 at 23:13
  • 1
    That's strange. Maybe try adding some sample JSON to your answer it might help others try to figure out how to best decode your data. – The Swift Coder Feb 21 '22 at 05:42
  • I figured it out finally - filtering an enum in Swift isn't straight-forward. ` let featuresWithgMultiPolygons = featuresCollection.filter { if case .multiPolygon = $0.geometry { return true } return false }` worked. – Jeff Ericson Feb 21 '22 at 17:57