tile38/vendor/github.com/tidwall/geoindex/algo/box.go

72 lines
1.9 KiB
Go

package algo
// Box performs simple box-distance algorithm on rectangles. When wrapX
// is provided, the operation does a cylinder wrapping of the X value to allow
// for antimeridian calculations. When itemDist is provided (not nil), it
// becomes the caller's responsibility to return the box-distance.
func Box(
targetMin, targetMax [2]float64, wrapX bool,
itemDist func(min, max [2]float64, data interface{}) float64,
) (
algo func(min, max [2]float64, data interface{}, item bool) (dist float64),
) {
return func(min, max [2]float64, data interface{}, item bool) (dist float64) {
if item && itemDist != nil {
return itemDist(min, max, data)
}
return BoxDistCalc(targetMin, targetMax, min, max, wrapX)
}
}
func mmin(x, y float64) float64 {
if x < y {
return x
}
return y
}
func mmax(x, y float64) float64 {
if x > y {
return x
}
return y
}
// BoxDistCalc returns the distance from rectangle A to rectangle B. When wrapX
// is provided, the operation does a cylinder wrapping of the X value to allow
// for antimeridian calculations.
func BoxDistCalc(aMin, aMax, bMin, bMax [2]float64, wrapX bool) float64 {
var dist float64
var squared float64
// X
squared = mmax(aMin[0], bMin[0]) - mmin(aMax[0], bMax[0])
if wrapX {
squaredLeft := mmax(aMin[0]-360, bMin[0]) - mmin(aMax[0]-360, bMax[0])
squaredRight := mmax(aMin[0]+360, bMin[0]) - mmin(aMax[0]+360, bMax[0])
squared = mmin(squared, mmin(squaredLeft, squaredRight))
}
if squared > 0 {
dist += squared * squared
}
// Y
squared = mmax(aMin[1], bMin[1]) - mmin(aMax[1], bMax[1])
if squared > 0 {
dist += squared * squared
}
return dist
}
// contains return struct when b is fully contained inside of n
func intersects(aMin, aMax, bMin, bMax [2]float64) bool {
if bMin[0] > aMax[0] || bMax[0] < aMin[0] {
return false
}
if bMin[1] > aMax[1] || bMax[1] < aMin[1] {
return false
}
return true
}