mapbox-gl-native icon indicating copy to clipboard operation
mapbox-gl-native copied to clipboard

geojson "LineString" features converted to MGLMultiPolylineFeature if "time" property is present

Open jrobinson01 opened this issue 4 years ago • 1 comments

This took me ages to debug. I have a geojson file consisting of about 8 "LineString" type features. In some code to select a single feature (layer), I was casting each feature as an MGLPolylineFeature but one of them kept giving me trouble, even though it's type in geojson was "type: "LineString", and it's coordinates property conformed to the spec. It turns out that, if the Feature had a "time" property, something somewhere was treating it as a MGLMultiPolylineFeature and throwing errors where I was casting it as MGLPolylineFeature.

Steps to reproduce

  1. create a geojson file with a LineString type feature.
  2. add a "time" property to it's "properties" block
  3. Create a source from the geojson, draw a line shape and then log the type of the feature.

Expected behavior

The feature should not be MGLMultiPolyline unless it's coordinates is an array of PointString coordinates.

Actual behavior

The feature is type MGLMultiPolyline instead of MGLPolyline

Configuration

Mapbox SDK versions: v6.3.0 iOS/macOS versions: Device/simulator models: Xcode version:

jrobinson01 avatar May 01 '21 02:05 jrobinson01

I was wrong. I don't understand how layers and features are built. I'm using the following to determine what feature was clicked, and then (later) hacking about to display the layer it belongs to (based on a "layerKey" property I'm setting in geojson):

    @objc @IBAction func handleMapTap(sender: UITapGestureRecognizer) {
        // Get the CGPoint where the user tapped.
        let spot = sender.location(in: mapView)
        // Access the features at that point within the state layer.
        let features = mapView.visibleFeatures(at: spot)
        // find the first feature with a "layerKey" attribute
        if let index = features.firstIndex(where: { (feature) -> Bool in
           return feature.attribute(forKey: "layerKey") != nil
        }){
            // currently sometimes failing, if feature is type MGLMultiPolylineFeature instead of MGLPolylineFeature.
            let feature = features[index]  as! MGLPolylineFeature
//            print("feature bounds: ", feature.overlayBounds)
            let layerKey = feature.attribute(forKey: "layerKey") as? String
            let difficulty = feature.attribute(forKey:"difficulty") as? String
            let miles = feature.attribute(forKey:"miles") as? Double
            let bounds = feature.overlayBounds // doesn't exist on MGLFeature
            let trail = Trail(layerKey:layerKey!, difficulty:difficulty!, miles:miles!, bounds:bounds)
            selectTrail(trail: trail)
        } else {
            selectTrail(trail: nil)
        }
    }

It seems like, depending on where in the feature I click (so far, it seems like it's only in one particular tile), I either get a feature that is type MGLMultiPolylineFeature of MGLPolylineFeature. My immediate problem is that I don't know how to cast as either or (or if that's a bad idea in general). My probably bigger problem is that I'm going about this all wrong.

jrobinson01 avatar May 01 '21 12:05 jrobinson01