github.com/pavlo67/common@v0.5.3/common/geolib/point.go (about) 1 package geolib 2 3 import ( 4 "math" 5 6 "github.com/pavlo67/common/common/mathlib" 7 8 geo "github.com/kellydunn/golang-geo" 9 "github.com/pavlo67/common/common/mathlib/plane" 10 // geo "github.com/billups/golang-geo" 11 ) 12 13 const DistanceEps = 1. 14 15 type Point struct { 16 Lat, Lon Degrees 17 } 18 19 type Direction struct { 20 Bearing 21 Distance float64 22 } 23 24 func (dir Direction) Moving() plane.Point2 { 25 return dir.Bearing.Point(dir.Distance) 26 } 27 28 const StepDistanceEps = 1e-2 29 30 // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames 31 32 func (p Point) Tile(zoom int) Tile { 33 // TODO!!! check zoom 34 35 tile := Tile{Zoom: zoom} 36 37 n := math.Exp2(float64(zoom)) 38 39 tile.X = int(math.Floor(float64((p.Lon+180.0)/360.0) * n)) 40 if float64(tile.X) >= n { 41 tile.X = int(n - 1) 42 } 43 44 latAngle := float64(p.Lat) * math.Pi / 180 45 tile.Y = int(math.Floor(n * (1 - math.Log(math.Tan(latAngle)+1/math.Cos(latAngle))/math.Pi) / 2)) 46 47 // log.Print(p, zoom, tile) 48 49 return tile 50 } 51 52 func (p Point) MovedBeared(bearing Bearing, moving plane.Point2) Point { 53 var geoPointStepped Point 54 55 if moving.Radius() <= StepDistanceEps { 56 geoPointStepped = p 57 58 } else { 59 stepBeared := moving.RotateByAngle(bearing.XToYAngleFromOy()) 60 geoPointStepped = p.MovedAt(stepBeared) 61 62 } 63 64 return Point{ 65 Degrees(mathlib.Round(float64(geoPointStepped.Lat), 6)), 66 Degrees(mathlib.Round(float64(geoPointStepped.Lon), 6))} 67 } 68 69 func (p Point) Geo() geo.Point { 70 return *geo.NewPoint(float64(p.Lat), float64(p.Lon)) 71 } 72 73 func (p Point) MovedAt(moving plane.Point2) Point { 74 if moving.X == 0 && moving.Y == 0 { 75 return p 76 } 77 78 dxKm, dyKm := moving.X*0.001, moving.Y*0.001 79 80 bearing := BearingFromPoint(plane.Point2{dxKm, dyKm}) 81 82 geoPoint := p.Geo() 83 84 // geoPoint.PointAtDistanceAndBearing() requires distance in kilometers 85 geoPointNew := geoPoint.PointAtDistanceAndBearing(math.Sqrt(dxKm*dxKm+dyKm*dyKm), float64(bearing)) 86 87 return Point{Degrees(geoPointNew.Lat()), Degrees(geoPointNew.Lng())} 88 } 89 90 func (p Point) PointAtDirection(dir Direction) Point { 91 geoPoint := p.Geo() 92 93 // geoPoint.PointAtDistanceAndBearing() requires distance in kilometers 94 geoPointNew := geoPoint.PointAtDistanceAndBearing(dir.Distance*0.001, float64(dir.Bearing)) 95 96 return Point{Degrees(geoPointNew.Lat()), Degrees(geoPointNew.Lng())} 97 } 98 99 func (p Point) BearingTo(p1 Point) Bearing { 100 geoPoint, geoPoint1 := p.Geo(), p1.Geo() 101 return Bearing(geoPoint.BearingTo(&geoPoint1)) 102 } 103 104 func (p Point) DistanceTo(p1 Point) float64 { 105 geoPoint, geoPoint1 := p.Geo(), p1.Geo() 106 107 // geoPoint.GreatCircleDistance(&geoPoint1) returns distance in kilometers 108 return 1000 * geoPoint.GreatCircleDistance(&geoPoint1) 109 } 110 111 func (p Point) DirectionTo(p1 Point) Direction { 112 geoPoint, geoPoint1 := p.Geo(), p1.Geo() 113 return Direction{ 114 Bearing(geoPoint.BearingTo(&geoPoint1)), 115 1000 * geoPoint.GreatCircleDistance(&geoPoint1), 116 } 117 } 118 119 func (geoPoint Point) MissFrom(geoPointReal Point) (missPoint plane.Point2, miss float64, bearing Bearing) { 120 missDirection := geoPointReal.DirectionTo(geoPoint) 121 122 return missDirection.Moving(), missDirection.Distance, missDirection.Bearing 123 }