diff --git a/util/geof/geohash.go b/util/geof/geohash.go new file mode 100644 index 00000000..2c6eb764 --- /dev/null +++ b/util/geof/geohash.go @@ -0,0 +1,111 @@ +// Copyright © 2016 Abcum Ltd +// +// 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. + +package geof + +import ( + "bytes" + + "github.com/abcum/surreal/sql" +) + +var bits = []int{16, 8, 4, 2, 1} + +var latmax = []float64{-90, 90} + +var lngmax = []float64{-180, 180} + +var base32 = []byte("0123456789bcdefghjkmnpqrstuvwxyz") + +func refine(interval []float64, cd, mask int) []float64 { + if cd&mask > 0 { + interval[0] = (interval[0] + interval[1]) / 2 + } else { + interval[1] = (interval[0] + interval[1]) / 2 + } + return interval +} + +func GeohashDecode(hash string) *sql.Point { + + isEven := true + lat := latmax + lng := lngmax + latErr := float64(90) + lngErr := float64(180) + var c string + var cd int + + for i := 0; i < len(hash); i++ { + c = hash[i : i+1] + cd = bytes.Index(base32, []byte(c)) + for j := 0; j < 5; j++ { + if isEven { + lngErr /= 2 + lng = refine(lng, cd, bits[j]) + } else { + latErr /= 2 + lat = refine(lat, cd, bits[j]) + } + isEven = !isEven + } + } + + return sql.NewPoint( + (lat[0]+lat[1])/2, + (lng[0]+lng[1])/2, + ) + +} + +func GeohashEncode(point *sql.Point, precision int64) string { + + isEven := true + lat := []float64{-90, 90} + lng := []float64{-180, 180} + bit := 0 + ch := 0 + var geohash bytes.Buffer + var mid float64 + for geohash.Len() < int(precision) { + if isEven { + mid = (lng[0] + lng[1]) / 2 + if point.LO > mid { + ch |= bits[bit] + lng[0] = mid + } else { + lng[1] = mid + } + } else { + mid = (lat[0] + lat[1]) / 2 + if point.LA > mid { + ch |= bits[bit] + lat[0] = mid + } else { + lat[1] = mid + } + } + isEven = !isEven + if bit < 4 { + bit++ + } else { + geohash.WriteByte(base32[ch]) + bit = 0 + ch = 0 + } + } + + return geohash.String() + +} diff --git a/util/geof/haversine.go b/util/geof/haversine.go new file mode 100644 index 00000000..e37bbe6b --- /dev/null +++ b/util/geof/haversine.go @@ -0,0 +1,34 @@ +// Copyright © 2016 Abcum Ltd +// +// 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. + +package geof + +import ( + "math" + + "github.com/abcum/surreal/sql" +) + +const earthr float64 = 6371000 + +const radian float64 = math.Pi / 180 + +func Haversine(a, b *sql.Point) float64 { + lata, lnga := a.LA*radian, a.LO*radian + latb, lngb := b.LA*radian, b.LO*radian + latc, lngc := lata-latb, lnga-lngb + dis := math.Pow(math.Sin(latc/2), 2) + math.Cos(lata)*math.Cos(latb)*math.Pow(math.Sin(lngc/2), 2) + c := 2 * math.Atan2(math.Sqrt(dis), math.Sqrt(1-dis)) + return earthr * c +} diff --git a/util/geof/inside.go b/util/geof/inside.go new file mode 100644 index 00000000..48134f53 --- /dev/null +++ b/util/geof/inside.go @@ -0,0 +1,19 @@ +// Copyright © 2016 Abcum Ltd +// +// 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. + +package geof + +func Inside(a, b interface{}) bool { + return false +} diff --git a/util/geof/intersects.go b/util/geof/intersects.go new file mode 100644 index 00000000..df53d6c1 --- /dev/null +++ b/util/geof/intersects.go @@ -0,0 +1,19 @@ +// Copyright © 2016 Abcum Ltd +// +// 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. + +package geof + +func Intersects(a, b interface{}) bool { + return false +}