tidwall / geojson

GeoJSON for Go. Used by Tile38
MIT License
130 stars 28 forks source link

FeatureCollection.ForEach only iterates geometry #17

Closed iwpnd closed 2 years ago

iwpnd commented 2 years ago

Hi :wave:

I want to load a geojson with a feature collection and iterate over the features with the ForEach message that the FeatureCollection provides.

func main() {
    file, err := ioutil.ReadFile(path)

    if err != nil {
        return err
    }
    fc, err := geojson.Parse(string(file), nil)
    if err != nil {
        return err
    }
    fc.ForEach(func(o geojson.Object) bool {
        if o.Empty() {
            return true
    }
    fmt.Println(o)
        return true
    })
}

>> {"type":"Polygon","coordinates":[[[13.107376098632812,52.37769505233968],[13.699264526367188,52.37769505233968],[13.699264526367188,52.63973017532399],[13.107376098632812,52.63973017532399],[13.107376098632812,52.37769505233968]]]}

If I run this I would expect to iterate over the an array of Feature and not Polygon.

Is this intentional and I have to rethink my approach?

iwpnd commented 2 years ago

I doubled checked the docs and noticed Children() that I could iterate over. A FeatureCollection is supposed to inherit Children() from a Collection, but doesn't so I'm stuck again. :/

tidwall commented 2 years ago

Hi Ben,

A FeatureCollection should inherit Collection, and it does include a Children and ForEach functions. Both should be effectively the same thing, except ForEach is exposed to all Object types, while Children really only indented for FeatureCollection and GeometryCollection types.

That said, I just tested this code to see what you are talking about.

https://play.golang.org/p/UW-w4T3nWvJ

package main

import (
    "fmt"

    "github.com/tidwall/geojson"
)

func main() {
    json := `{"type":"FeatureCollection","features":[
        {"type":"Feature","id":"A","geometry":{"type":"Point","coordinates":[1,2]},"properties":{}},
        {"type":"Feature","id":"B","geometry":{"type":"Point","coordinates":[3,4]},"properties":{}},
        {"type":"Feature","id":"C","geometry":{"type":"Point","coordinates":[5,6]},"properties":{}},
        {"type":"Feature","id":"D","geometry":{"type":"Point","coordinates":[7,8]},"properties":{}}
    ]}`

    f, err := geojson.Parse(json, nil)
    if err != nil {
        panic(err)
    }
    objsA := f.(*geojson.FeatureCollection).Children()
    var objsB []geojson.Object
    f.ForEach(func(geom geojson.Object) bool {
        objsB = append(objsB, geom)
        return true
    })
    for i := 0; i < len(objsA) && i < len(objsB); i++ {
        fmt.Printf("%d: %s\n%d: %s\n", i, objsA[i], i, objsB[i])
    }
}

Output

0: {"type":"Feature","geometry":{"type":"Point","coordinates":[1,2]},"id":"A","properties":{}}
0: {"type":"Point","coordinates":[1,2]}
1: {"type":"Feature","geometry":{"type":"Point","coordinates":[3,4]},"id":"B","properties":{}}
1: {"type":"Point","coordinates":[3,4]}
2: {"type":"Feature","geometry":{"type":"Point","coordinates":[5,6]},"id":"C","properties":{}}
2: {"type":"Point","coordinates":[5,6]}
3: {"type":"Feature","geometry":{"type":"Point","coordinates":[7,8]},"id":"D","properties":{}}
3: {"type":"Point","coordinates":[7,8]}

This is clearly wrong. It should output the entire Feature. 🤦‍♂️

tidwall commented 2 years ago

Found the issue. Just pushed a fix, see v1.3.1

iwpnd commented 2 years ago

Awesome, thank you! 🙏

tidwall commented 2 years ago

You're welcome and thanks for reporting. :)