Improve geometry polygon searching functionality
This commit is contained in:
parent
e2635e8cf9
commit
27b80ceb8e
3 changed files with 184 additions and 0 deletions
114
db/fetch.go
114
db/fetch.go
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
"github.com/abcum/surreal/cnf"
|
||||
"github.com/abcum/surreal/sql"
|
||||
"github.com/abcum/surreal/util/geof"
|
||||
"github.com/abcum/surreal/util/data"
|
||||
"github.com/abcum/surreal/util/deep"
|
||||
"github.com/abcum/surreal/util/fncs"
|
||||
|
@ -708,6 +709,41 @@ func binaryCheck(op sql.Token, l, r, lo, ro interface{}, d *data.Doc) interface{
|
|||
return chkArrayR(op, l, r)
|
||||
}
|
||||
|
||||
case *sql.Point:
|
||||
switch r := r.(type) {
|
||||
case *sql.Point:
|
||||
return chkPoint(op, l, r)
|
||||
case *sql.Polygon:
|
||||
switch op {
|
||||
case sql.INS:
|
||||
return geof.Inside(l, r) == true
|
||||
case sql.NIS:
|
||||
return geof.Inside(l, r) == false
|
||||
}
|
||||
}
|
||||
|
||||
case *sql.Polygon:
|
||||
switch r := r.(type) {
|
||||
case *sql.Point:
|
||||
switch op {
|
||||
case sql.SIN:
|
||||
return geof.Contains(l, r) == true
|
||||
case sql.SNI:
|
||||
return geof.Contains(l, r) == false
|
||||
}
|
||||
case []interface{}:
|
||||
if p, ok := geof.Point(r); ok {
|
||||
switch op {
|
||||
case sql.SIN:
|
||||
return geof.Contains(l, p) == true
|
||||
case sql.SNI:
|
||||
return geof.Contains(l, p) == false
|
||||
}
|
||||
} else {
|
||||
return chkPolygonL(op, l, r)
|
||||
}
|
||||
}
|
||||
|
||||
case bool:
|
||||
switch r := r.(type) {
|
||||
case bool:
|
||||
|
@ -822,6 +858,8 @@ func binaryCheck(op sql.Token, l, r, lo, ro interface{}, d *data.Doc) interface{
|
|||
return chkArray(op, l, r)
|
||||
case map[string]interface{}:
|
||||
return chkArrayL(op, l, r)
|
||||
case *sql.Polygon:
|
||||
return chkPolygonR(op, l, r)
|
||||
}
|
||||
|
||||
case map[string]interface{}:
|
||||
|
@ -972,6 +1010,16 @@ func chkThing(op sql.Token, a, b *sql.Thing) (val bool) {
|
|||
return negOp(op)
|
||||
}
|
||||
|
||||
func chkPoint(op sql.Token, a, b *sql.Point) (val bool) {
|
||||
switch op {
|
||||
case sql.EQ:
|
||||
return a.LA == b.LA && a.LO == b.LO
|
||||
case sql.NEQ:
|
||||
return a.LA != b.LA || a.LO != b.LO
|
||||
}
|
||||
return negOp(op)
|
||||
}
|
||||
|
||||
func chkRegex(op sql.Token, a string, r *regexp.Regexp) (val bool) {
|
||||
switch op {
|
||||
case sql.EQ:
|
||||
|
@ -1004,6 +1052,72 @@ func chkObject(op sql.Token, m map[string]interface{}, i interface{}) (val bool)
|
|||
return negOp(op)
|
||||
}
|
||||
|
||||
func chkPolygonL(op sql.Token, a *sql.Polygon, b []interface{}) (val bool) {
|
||||
switch op {
|
||||
case sql.CONTAINSALL:
|
||||
for _, v := range b {
|
||||
if p, ok := geof.Point(v); ok {
|
||||
if geof.Contains(a, p) == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
case sql.CONTAINSSOME:
|
||||
for _, v := range b {
|
||||
if p, ok := geof.Point(v); ok {
|
||||
if geof.Contains(a, p) == true {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
case sql.CONTAINSNONE:
|
||||
for _, v := range b {
|
||||
if p, ok := geof.Point(v); ok {
|
||||
if geof.Contains(a, p) == true {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func chkPolygonR(op sql.Token, a []interface{}, b *sql.Polygon) (val bool) {
|
||||
switch op {
|
||||
case sql.ALLCONTAINEDIN:
|
||||
for _, v := range a {
|
||||
if p, ok := geof.Point(v); ok {
|
||||
if geof.Contains(b, p) == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
case sql.SOMECONTAINEDIN:
|
||||
for _, v := range a {
|
||||
if p, ok := geof.Point(v); ok {
|
||||
if geof.Contains(b, p) == true {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
case sql.NONECONTAINEDIN:
|
||||
for _, v := range a {
|
||||
if p, ok := geof.Point(v); ok {
|
||||
if geof.Contains(b, p) == true {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func chkArrayL(op sql.Token, a []interface{}, i interface{}) (val bool) {
|
||||
switch op {
|
||||
case sql.EQ:
|
||||
|
|
|
@ -144,6 +144,10 @@ func ensurePoint(val interface{}) (out *sql.Point, ok bool) {
|
|||
switch val := val.(type) {
|
||||
case *sql.Point:
|
||||
return val, true
|
||||
case []interface{}:
|
||||
if p := ensureFloats(val); len(p) == 2 {
|
||||
return sql.NewPoint(p[0], p[1]), true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
|
66
util/geof/point.go
Normal file
66
util/geof/point.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
// 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 (
|
||||
"strconv"
|
||||
|
||||
"github.com/abcum/surreal/sql"
|
||||
)
|
||||
|
||||
func ensureSlice(args interface{}) (out []interface{}, ok bool) {
|
||||
if i, ok := args.([]interface{}); ok {
|
||||
return i, true
|
||||
} else {
|
||||
return []interface{}{args}, false
|
||||
}
|
||||
}
|
||||
|
||||
func ensureFloats(args interface{}) (out []float64) {
|
||||
arr, _ := ensureSlice(args)
|
||||
for _, val := range arr {
|
||||
switch val := val.(type) {
|
||||
case int:
|
||||
out = append(out, float64(val))
|
||||
case int64:
|
||||
out = append(out, float64(val))
|
||||
case uint:
|
||||
out = append(out, float64(val))
|
||||
case uint64:
|
||||
out = append(out, float64(val))
|
||||
case float32:
|
||||
out = append(out, float64(val))
|
||||
case float64:
|
||||
out = append(out, float64(val))
|
||||
case string:
|
||||
if val, err := strconv.ParseFloat(val, 64); err == nil {
|
||||
out = append(out, float64(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Point(val interface{}) (out *sql.Point, ok bool) {
|
||||
switch val := val.(type) {
|
||||
case *sql.Point:
|
||||
return val, true
|
||||
case []interface{}:
|
||||
if p := ensureFloats(val); len(p) == 2 {
|
||||
return sql.NewPoint(p[0], p[1]), true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
Loading…
Reference in a new issue