mirror of https://github.com/tidwall/tile38.git
96 lines
3.0 KiB
Go
96 lines
3.0 KiB
Go
|
// Copyright 2018 Joshua J Baker. All rights reserved.
|
|||
|
// Use of this source code is governed by an MIT-style
|
|||
|
// license that can be found in the LICENSE file.
|
|||
|
|
|||
|
package geo
|
|||
|
|
|||
|
import (
|
|||
|
"math"
|
|||
|
)
|
|||
|
|
|||
|
const (
|
|||
|
earthRadius = 6371e3
|
|||
|
radians = math.Pi / 180
|
|||
|
degrees = 180 / math.Pi
|
|||
|
)
|
|||
|
|
|||
|
// DistanceTo return the distance in meteres between two point.
|
|||
|
func DistanceTo(latA, lonA, latB, lonB float64) (meters float64) {
|
|||
|
φ1 := latA * radians
|
|||
|
λ1 := lonA * radians
|
|||
|
φ2 := latB * radians
|
|||
|
λ2 := lonB * radians
|
|||
|
Δφ := φ2 - φ1
|
|||
|
Δλ := λ2 - λ1
|
|||
|
a := math.Sin(Δφ/2)*math.Sin(Δφ/2) +
|
|||
|
math.Cos(φ1)*math.Cos(φ2)*math.Sin(Δλ/2)*math.Sin(Δλ/2)
|
|||
|
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
|||
|
return earthRadius * c
|
|||
|
}
|
|||
|
|
|||
|
// DestinationPoint return the destination from a point based on a
|
|||
|
// distance and bearing.
|
|||
|
func DestinationPoint(lat, lon, meters, bearingDegrees float64) (
|
|||
|
destLat, destLon float64,
|
|||
|
) {
|
|||
|
// see http://williams.best.vwh.net/avform.htm#LL
|
|||
|
δ := meters / earthRadius // angular distance in radians
|
|||
|
θ := bearingDegrees * radians
|
|||
|
φ1 := lat * radians
|
|||
|
λ1 := lon * radians
|
|||
|
φ2 := math.Asin(math.Sin(φ1)*math.Cos(δ) +
|
|||
|
math.Cos(φ1)*math.Sin(δ)*math.Cos(θ))
|
|||
|
λ2 := λ1 + math.Atan2(math.Sin(θ)*math.Sin(δ)*math.Cos(φ1),
|
|||
|
math.Cos(δ)-math.Sin(φ1)*math.Sin(φ2))
|
|||
|
λ2 = math.Mod(λ2+3*math.Pi, 2*math.Pi) - math.Pi // normalise to -180..+180°
|
|||
|
return φ2 * degrees, λ2 * degrees
|
|||
|
}
|
|||
|
|
|||
|
// BearingTo returns the (initial) bearing from point 'A' to point 'B'.
|
|||
|
func BearingTo(latA, lonA, latB, lonB float64) float64 {
|
|||
|
// tanθ = sinΔλ⋅cosφ2 / cosφ1⋅sinφ2 − sinφ1⋅cosφ2⋅cosΔλ
|
|||
|
// see mathforum.org/library/drmath/view/55417.html for derivation
|
|||
|
|
|||
|
φ1 := latA * radians
|
|||
|
φ2 := latB * radians
|
|||
|
Δλ := (lonB - lonA) * radians
|
|||
|
y := math.Sin(Δλ) * math.Cos(φ2)
|
|||
|
x := math.Cos(φ1)*math.Sin(φ2) - math.Sin(φ1)*math.Cos(φ2)*math.Cos(Δλ)
|
|||
|
θ := math.Atan2(y, x)
|
|||
|
|
|||
|
return math.Mod(θ*degrees+360, 360)
|
|||
|
}
|
|||
|
|
|||
|
// // SegmentIntersectsCircle ...
|
|||
|
// func SegmentIntersectsCircle(
|
|||
|
// startLat, startLon, endLat, endLon, centerLat, centerLon, meters float64,
|
|||
|
// ) bool {
|
|||
|
// // These are faster checks.
|
|||
|
// // If they succeed there's no need do complicate things.
|
|||
|
// if DistanceTo(startLat, startLon, centerLat, centerLon) <= meters {
|
|||
|
// return true
|
|||
|
// }
|
|||
|
// if DistanceTo(endLat, endLon, centerLat, centerLon) <= meters {
|
|||
|
// return true
|
|||
|
// }
|
|||
|
|
|||
|
// // Distance between start and end
|
|||
|
// l := DistanceTo(startLat, startLon, endLat, endLon)
|
|||
|
|
|||
|
// // Unit direction vector
|
|||
|
// dLat := (endLat - startLat) / l
|
|||
|
// dLon := (endLon - startLon) / l
|
|||
|
|
|||
|
// // Point of the line closest to the center
|
|||
|
// t := dLon*(centerLon-startLon) + dLat*(centerLat-startLat)
|
|||
|
// pLat := t*dLat + startLat
|
|||
|
// pLon := t*dLon + startLon
|
|||
|
// if pLon < startLon || pLon > endLon || pLat < startLat || pLat > endLat {
|
|||
|
// // closest point is outside the segment
|
|||
|
// return false
|
|||
|
// }
|
|||
|
|
|||
|
// // Distance from the closest point to the center
|
|||
|
// return DistanceTo(centerLat, centerLon, pLat, pLon) <= meters
|
|||
|
// }
|