// Package geoutils provides utility functions to handler geographic calculations such as distance between geometries. package geoutils import ( "math" "github.com/paulmach/orb" "github.com/paulmach/orb/geo" ) // DistanceFromLineString provides the shorteds distance between a point and a linestring. // It returns the distance in meters, and the index of the closest linestring segment to the point func DistanceFromLineString(point orb.Point, lineString orb.LineString) (distance float64, closestIndex int) { minDistance := math.Inf(1) closest := -1 for i := 0; i < len(lineString)-1; i++ { a := lineString[i] b := lineString[i+1] pointOnSegment := projectToSegment(point, a, b) dist := geo.Distance(point, pointOnSegment) if dist < minDistance { minDistance = dist closest = i } } // log.Debug(). // Float64("min distance", minDistance). // Int("index", closest). // Any("point", point). // Msg("minimum distance to polyline") return minDistance, closest } // projectToSegment projects the point to the segment. This function is used in DistanceFromLineString for point-to-segment distance calculation func projectToSegment(point, a, b orb.Point) orb.Point { x := a[0] y := a[1] dx := b[0] - x dy := b[1] - y if dx != 0 || dy != 0 { t := ((point[0]-x)*dx + (point[1]-y)*dy) / (dx*dx + dy*dy) if t > 1 { x = b[0] y = b[1] } else if t > 0 { x += dx * t y += dy * t } } return orb.Point{x, y} }