mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 22:41:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			111 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			111 lines
		
	
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //  Copyright (c) 2019 Couchbase, Inc.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| // 		http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| // This implementation is inspired from the geohash-js
 | |
| // ref: https://github.com/davetroy/geohash-js
 | |
| 
 | |
| package geo
 | |
| 
 | |
| // encoding encapsulates an encoding defined by a given base32 alphabet.
 | |
| type encoding struct {
 | |
| 	enc string
 | |
| 	dec [256]byte
 | |
| }
 | |
| 
 | |
| // newEncoding constructs a new encoding defined by the given alphabet,
 | |
| // which must be a 32-byte string.
 | |
| func newEncoding(encoder string) *encoding {
 | |
| 	e := new(encoding)
 | |
| 	e.enc = encoder
 | |
| 	for i := 0; i < len(e.dec); i++ {
 | |
| 		e.dec[i] = 0xff
 | |
| 	}
 | |
| 	for i := 0; i < len(encoder); i++ {
 | |
| 		e.dec[encoder[i]] = byte(i)
 | |
| 	}
 | |
| 	return e
 | |
| }
 | |
| 
 | |
| // base32encoding with the Geohash alphabet.
 | |
| var base32encoding = newEncoding("0123456789bcdefghjkmnpqrstuvwxyz")
 | |
| 
 | |
| var masks = []uint64{16, 8, 4, 2, 1}
 | |
| 
 | |
| // DecodeGeoHash decodes the string geohash faster with
 | |
| // higher precision. This api is in experimental phase.
 | |
| func DecodeGeoHash(geoHash string) (float64, float64) {
 | |
| 	even := true
 | |
| 	lat := []float64{-90.0, 90.0}
 | |
| 	lon := []float64{-180.0, 180.0}
 | |
| 
 | |
| 	for i := 0; i < len(geoHash); i++ {
 | |
| 		cd := uint64(base32encoding.dec[geoHash[i]])
 | |
| 		for j := 0; j < 5; j++ {
 | |
| 			if even {
 | |
| 				if cd&masks[j] > 0 {
 | |
| 					lon[0] = (lon[0] + lon[1]) / 2
 | |
| 				} else {
 | |
| 					lon[1] = (lon[0] + lon[1]) / 2
 | |
| 				}
 | |
| 			} else {
 | |
| 				if cd&masks[j] > 0 {
 | |
| 					lat[0] = (lat[0] + lat[1]) / 2
 | |
| 				} else {
 | |
| 					lat[1] = (lat[0] + lat[1]) / 2
 | |
| 				}
 | |
| 			}
 | |
| 			even = !even
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return (lat[0] + lat[1]) / 2, (lon[0] + lon[1]) / 2
 | |
| }
 | |
| 
 | |
| func EncodeGeoHash(lat, lon float64) string {
 | |
| 	even := true
 | |
| 	lats := []float64{-90.0, 90.0}
 | |
| 	lons := []float64{-180.0, 180.0}
 | |
| 	precision := 12
 | |
| 	var ch, bit uint64
 | |
| 	var geoHash string
 | |
| 
 | |
| 	for len(geoHash) < precision {
 | |
| 		if even {
 | |
| 			mid := (lons[0] + lons[1]) / 2
 | |
| 			if lon > mid {
 | |
| 				ch |= masks[bit]
 | |
| 				lons[0] = mid
 | |
| 			} else {
 | |
| 				lons[1] = mid
 | |
| 			}
 | |
| 		} else {
 | |
| 			mid := (lats[0] + lats[1]) / 2
 | |
| 			if lat > mid {
 | |
| 				ch |= masks[bit]
 | |
| 				lats[0] = mid
 | |
| 			} else {
 | |
| 				lats[1] = mid
 | |
| 			}
 | |
| 		}
 | |
| 		even = !even
 | |
| 		if bit < 4 {
 | |
| 			bit++
 | |
| 		} else {
 | |
| 			geoHash += string(base32encoding.enc[ch])
 | |
| 			ch = 0
 | |
| 			bit = 0
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return geoHash
 | |
| }
 |