golang / geo

S2 geometry library in Go
Apache License 2.0
1.69k stars 182 forks source link

Memory Leak when a loop contains point multiple time #99

Open kapsteur opened 1 year ago

kapsteur commented 1 year ago

I noticed a case when my transformation of polygons to cells take long time and lot of memory. After some investigations I found a reproductible case. It seem, when a polygons contains multiple time the same point the S2 library loop on something.

I created a test case :

package main

import (
    "encoding/json"
    "log"
    "time"

    "github.com/golang/geo/s2"
)

const (
    arrayOfPointsOk = `[[49.3953,1.9212],[49.3952,1.9214],[49.3951,1.9216],[49.3950,1.9220],[49.3949,1.9223],[49.3953,1.9212]]`
    arrayOfPointsNotOk  = `[[49.3953,1.9212],[49.3953,1.9212],[49.3952,1.9214],[49.3951,1.9216],[49.3950,1.9220],[49.3949,1.9223],[49.3953,1.9212]]`
)

func main() {

    t1 := time.Now().UTC().UnixMilli()
    pointsFloat := make([][]float64, 0)

    err := json.Unmarshal([]byte(arrayOfPointsNotOk), &pointsFloat)
    if err != nil {
        log.Fatal(err)
    }

    t2 := time.Now().UnixMilli()
    log.Printf("pointsFloat:%d t:%dms", len(pointsFloat), t2-t1)

    pointsS2 := make([]s2.Point, len(pointsFloat))
    for i, p := range pointsFloat {
        pointsS2[i] = s2.PointFromLatLng(s2.LatLngFromDegrees(p[0], p[1]))
    }

    t3 := time.Now().UnixMilli()
    log.Printf("pointsS2:%d  t:%dms", len(pointsS2), t3-t2)

    loopsS2 := s2.LoopFromPoints(pointsS2)

    t4 := time.Now().UnixMilli()
    log.Printf("loopsS2:%d  t:%dms", loopsS2.NumEdges(), t4-t3)

    ids := s2.SimpleRegionCovering(loopsS2, loopsS2.Edge(0).V0, 15)

    log.Printf("ids:%d  t:%dms", len(ids), time.Now().UnixMilli()-t4)

}
akhenakh commented 1 year ago

your loop is probably containing the world,rather than just the area you are expecting, check for clockwise ordering of your points

akhenakh commented 1 year ago

I've answered too fast, a loop can't have duplicates points, (not like geosjon polygon) and the result is probably your loop containing the world

// Loops are not allowed to have any duplicate vertices (whether adjacent or
// not).  Non-adjacent edges are not allowed to intersect, and furthermore edges
// of length 180 degrees are not allowed (i.e., adjacent vertices cannot be
// antipodal). Loops must have at least 3 vertices (except for the "empty" and
// "full" loops discussed below).