gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

latlng.go (3456B)


      1 // Copyright 2014 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package s2
     16 
     17 import (
     18 	"fmt"
     19 	"math"
     20 
     21 	"github.com/golang/geo/r3"
     22 	"github.com/golang/geo/s1"
     23 )
     24 
     25 const (
     26 	northPoleLat = s1.Angle(math.Pi/2) * s1.Radian
     27 	southPoleLat = -northPoleLat
     28 )
     29 
     30 // LatLng represents a point on the unit sphere as a pair of angles.
     31 type LatLng struct {
     32 	Lat, Lng s1.Angle
     33 }
     34 
     35 // LatLngFromDegrees returns a LatLng for the coordinates given in degrees.
     36 func LatLngFromDegrees(lat, lng float64) LatLng {
     37 	return LatLng{s1.Angle(lat) * s1.Degree, s1.Angle(lng) * s1.Degree}
     38 }
     39 
     40 // IsValid returns true iff the LatLng is normalized, with Lat ∈ [-π/2,π/2] and Lng ∈ [-π,π].
     41 func (ll LatLng) IsValid() bool {
     42 	return math.Abs(ll.Lat.Radians()) <= math.Pi/2 && math.Abs(ll.Lng.Radians()) <= math.Pi
     43 }
     44 
     45 // Normalized returns the normalized version of the LatLng,
     46 // with Lat clamped to [-π/2,π/2] and Lng wrapped in [-π,π].
     47 func (ll LatLng) Normalized() LatLng {
     48 	lat := ll.Lat
     49 	if lat > northPoleLat {
     50 		lat = northPoleLat
     51 	} else if lat < southPoleLat {
     52 		lat = southPoleLat
     53 	}
     54 	lng := s1.Angle(math.Remainder(ll.Lng.Radians(), 2*math.Pi)) * s1.Radian
     55 	return LatLng{lat, lng}
     56 }
     57 
     58 func (ll LatLng) String() string { return fmt.Sprintf("[%v, %v]", ll.Lat, ll.Lng) }
     59 
     60 // Distance returns the angle between two LatLngs.
     61 func (ll LatLng) Distance(ll2 LatLng) s1.Angle {
     62 	// Haversine formula, as used in C++ S2LatLng::GetDistance.
     63 	lat1, lat2 := ll.Lat.Radians(), ll2.Lat.Radians()
     64 	lng1, lng2 := ll.Lng.Radians(), ll2.Lng.Radians()
     65 	dlat := math.Sin(0.5 * (lat2 - lat1))
     66 	dlng := math.Sin(0.5 * (lng2 - lng1))
     67 	x := dlat*dlat + dlng*dlng*math.Cos(lat1)*math.Cos(lat2)
     68 	return s1.Angle(2*math.Atan2(math.Sqrt(x), math.Sqrt(math.Max(0, 1-x)))) * s1.Radian
     69 }
     70 
     71 // NOTE(mikeperrow): The C++ implementation publicly exposes latitude/longitude
     72 // functions. Let's see if that's really necessary before exposing the same functionality.
     73 
     74 func latitude(p Point) s1.Angle {
     75 	return s1.Angle(math.Atan2(p.Z, math.Sqrt(p.X*p.X+p.Y*p.Y))) * s1.Radian
     76 }
     77 
     78 func longitude(p Point) s1.Angle {
     79 	return s1.Angle(math.Atan2(p.Y, p.X)) * s1.Radian
     80 }
     81 
     82 // PointFromLatLng returns an Point for the given LatLng.
     83 // The maximum error in the result is 1.5 * dblEpsilon. (This does not
     84 // include the error of converting degrees, E5, E6, or E7 into radians.)
     85 func PointFromLatLng(ll LatLng) Point {
     86 	phi := ll.Lat.Radians()
     87 	theta := ll.Lng.Radians()
     88 	cosphi := math.Cos(phi)
     89 	return Point{r3.Vector{math.Cos(theta) * cosphi, math.Sin(theta) * cosphi, math.Sin(phi)}}
     90 }
     91 
     92 // LatLngFromPoint returns an LatLng for a given Point.
     93 func LatLngFromPoint(p Point) LatLng {
     94 	return LatLng{latitude(p), longitude(p)}
     95 }
     96 
     97 // ApproxEqual reports whether the latitude and longitude of the two LatLngs
     98 // are the same up to a small tolerance.
     99 func (ll LatLng) ApproxEqual(other LatLng) bool {
    100 	return ll.Lat.ApproxEqual(other.Lat) && ll.Lng.ApproxEqual(other.Lng)
    101 }