twpayne / go-geom

Package geom implements efficient geometry types for geospatial applications.
BSD 2-Clause "Simplified" License
841 stars 104 forks source link

Polygon intersection and containment #193

Open atombender opened 3 years ago

atombender commented 3 years ago

I'm looking for a way to use this library to check, using Cartesian coordinates:

I'm not seeing any exported functions for doing this. Is there any support for it, or should I look somewhere else?

From what I can tell, checking if a point is contained in a polygon can be accomplished this way:

func PolygonContainsPoint(polygon *geom.Polygon, p *geom.Point) bool {
    exterior := polygon.LinearRing(0)
    if !xy.IsPointInRing(geom.XY, p.Coords(), exterior.FlatCoords()) {
        return false
    }

    // Next rings are holes
    num := polygon.NumLinearRings()
    for i := 1; i < num; i++ {
        interior := polygon.LinearRing(i)
        if xy.IsPointInRing(geom.XY, p.Coords(), interior.FlatCoords()) {
            return false
        }
    }

    return true
}

Or? I'm not too familiar with rings or if this is how they're intended to be used. Either way, such a function would be a useful addition to this library, I think.

twpayne commented 3 years ago

Thank you @atombender for opening this issue :)

This library effectively contains three parts: a Go-friendly representation for geometry types, a set of packages to serialize and deserialize those types, and packages (like xy) that perform operations on geometries. The first two are solid, fast, and widely used. The third part, the xy package, is a contributed port of code from the Java Topology Suite. Sadly the xy package has not seen much love in the last few years.

The fix depends on your requirements:

atombender commented 3 years ago

Thanks for responding! After I wrote the comment, I went hunting for bindings to either GEOS or GDAL, and I ended up on this decent maintained fork of an old, abandoned set of bindings to GEOS, which seems like an absolutely solid library.

Your support for WKT/WKB was a life-saver. So now I read GeoSON into go-geom, then convert to GEOS to perform operations like the ones I need. Having to go through WKB is not optimal, but fortunately this is not on a fast path, and it looks like it would be feasible to write a translator if we should need more speed. My only complaint with this solution is the fact that the GEOS library is now a build dependency.

Geometry/geography libs for Go are lacking. I poked through so many pure Go libraries that provide a lot of trivial functionality (such as reading and writing GeoJSON), but fall short when it comes to the actual hard stuff. If you ever feel like sitting down and making the xy package more complete, that would be very cool indeed.

thomascoquet commented 1 year ago

@atombender You could give godal a try https://github.com/airbusgeo/godal/blob/main/godal.go#L2700

twpayne commented 1 year ago

Or better, go-geos now provides this functionality in Go using the battle-tested GEOS library. Note that GDAL is for data formats and GEOS is for geometric operations like polygon intersection and containment.