tile38/pkg/index/norm.go

125 lines
4.0 KiB
Go

package index
import "math"
// normPoint takes the latitude and longitude of one point and return the x,y position on a world map.
// The map bounds are minimum -180,-90 and maximum 180,90. These values are x,y; not lat,lon.
func normPoint(lat, lon float64) (x, y float64, normd bool) {
// Check if the rect is completely in bounds.
// This is likely to be the vast majority of cases.
if lon >= -180 && lon <= 180 && lat >= -90 && lat <= 90 {
return lon, lat, false
}
lat = math.Mod(lat, 360)
for lat < -90 || lat > 90 {
if lat < -90 {
lat = -90 - (90 + lat)
lon = 180 + lon
}
if lat > 90 {
lat = 90 + (90 - lat)
lon = 180 + lon
}
}
lon = math.Mod(lon, 360)
for lon < -180 {
lon += 360
}
for lon > 180 {
lon -= 360
}
return lon, lat, true
}
// normRect takes the latitude and longitude of two points which define a rectangle and returns an array of x,y rectangles on a world map.
// The map bounds are minimum -180,-90 and maximum 180,90. These values are x,y; not lat,lon.
func normRect(swLat, swLon, neLat, neLon float64) (mins, maxs [][]float64, normd bool) {
mins, maxs, normd = normRectStep(swLat, swLon, neLat, neLon, nil, nil, false)
return mins, maxs, normd
}
func normRectStep(swLat, swLon, neLat, neLon float64, mins, maxs [][]float64, normd bool) (minsOut, maxsOut [][]float64, normdOut bool) {
// Make sure that the northeast point is greater than the southwest point.
if neLat < swLat {
swLat, neLat, normd = neLat, swLat, true
}
if neLon < swLon {
swLon, neLon, normd = neLon, swLon, true
}
if swLon < -180 || neLon > 180 {
// The rect is horizontally out of bounds.
if neLon-swLon > 360 {
// The rect goes around the world. Just normalize to -180 to 180.
swLon = -180
neLon = 180
} else if swLon < -180 && neLon < -180 {
// The rect is way left. Move it into range.
// TODO: replace loops with math/mod.
for {
swLon += 360
neLon += 360
if swLon >= -180 || neLon >= -180 {
break
}
}
} else if swLon > 180 && neLon > 180 {
// The rect is way right. Move it into range.
// TODO: replace loops with math/mod.
for {
swLon -= 360
neLon -= 360
if swLon <= 180 || neLon <= 180 {
break
}
}
} else {
// The rect needs to be split into two.
if swLon < -180 {
mins, maxs, normd = normRectStep(swLat, 180+(180+swLon), neLat, 180, mins, maxs, normd)
mins, maxs, normd = normRectStep(swLat, -180, neLat, neLon, mins, maxs, normd)
} else if neLon > 180 {
mins, maxs, normd = normRectStep(swLat, swLon, neLat, 180, mins, maxs, normd)
mins, maxs, normd = normRectStep(swLat, -180, neLat, -180+(neLon-180), mins, maxs, normd)
} else {
panic("should not be reached")
}
return mins, maxs, true
}
return normRectStep(swLat, swLon, neLat, neLon, mins, maxs, true)
} else if swLat < -90 || neLat > 90 {
// The rect is vertically out of bounds.
if neLat-swLat > 360 {
// The rect goes around the world. Just normalize to -180 to 180.
swLat = -180
neLat = 180
} else if swLat < -90 && neLat < -90 {
swLat = -90 + (-90 - swLat)
neLat = -90 + (-90 - neLat)
swLon = swLon - 180
neLon = neLon - 180
} else if swLat > 90 && neLat > 90 {
swLat = 90 - (swLat - 90)
neLat = 90 - (neLat - 90)
swLon = swLon - 180
neLon = neLon - 180
} else {
if neLat > 90 {
mins, maxs, normd = normRectStep(swLat, swLon, 90, neLon, mins, maxs, normd)
mins, maxs, normd = normRectStep(90-(neLat-90), swLon-180, 90, neLon-180, mins, maxs, normd)
} else if swLat < -90 {
mins, maxs, normd = normRectStep(-90, swLon, neLat, neLon, mins, maxs, normd)
mins, maxs, normd = normRectStep(-90, swLon-180, -90-(90+swLat), neLon-180, mins, maxs, normd)
} else {
panic("should not be reached")
}
return mins, maxs, true
}
return normRectStep(swLat, swLon, neLat, neLon, mins, maxs, true)
} else {
// rect is completely in bounds.
mins = append(mins, []float64{swLon, swLat})
maxs = append(maxs, []float64{neLon, neLat})
return mins, maxs, normd
}
}