mirror of https://github.com/tidwall/tile38.git
Merge pull request #552 from rshura/clip-by
Add CLIPBY subcommand to INTERSECTS/WITHIN
This commit is contained in:
commit
1467cba769
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/tidwall/geojson/geometry"
|
"github.com/tidwall/geojson/geometry"
|
||||||
"github.com/tidwall/resp"
|
"github.com/tidwall/resp"
|
||||||
"github.com/tidwall/tile38/internal/bing"
|
"github.com/tidwall/tile38/internal/bing"
|
||||||
|
"github.com/tidwall/tile38/internal/clip"
|
||||||
"github.com/tidwall/tile38/internal/deadline"
|
"github.com/tidwall/tile38/internal/deadline"
|
||||||
"github.com/tidwall/tile38/internal/glob"
|
"github.com/tidwall/tile38/internal/glob"
|
||||||
)
|
)
|
||||||
|
@ -57,6 +58,119 @@ func (s liveFenceSwitches) usingLua() bool {
|
||||||
return len(s.whereevals) > 0
|
return len(s.whereevals) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseRectArea(ltyp string, vs []string) (nvs []string, rect *geojson.Rect, err error) {
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
switch ltyp {
|
||||||
|
default:
|
||||||
|
err = errNotRectangle
|
||||||
|
return
|
||||||
|
case "bounds":
|
||||||
|
var sminLat, sminLon, smaxlat, smaxlon string
|
||||||
|
if vs, sminLat, ok = tokenval(vs); !ok || sminLat == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if vs, sminLon, ok = tokenval(vs); !ok || sminLon == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if vs, smaxlat, ok = tokenval(vs); !ok || smaxlat == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if vs, smaxlon, ok = tokenval(vs); !ok || smaxlon == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var minLat, minLon, maxLat, maxLon float64
|
||||||
|
if minLat, err = strconv.ParseFloat(sminLat, 64); err != nil {
|
||||||
|
err = errInvalidArgument(sminLat)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if minLon, err = strconv.ParseFloat(sminLon, 64); err != nil {
|
||||||
|
err = errInvalidArgument(sminLon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if maxLat, err = strconv.ParseFloat(smaxlat, 64); err != nil {
|
||||||
|
err = errInvalidArgument(smaxlat)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if maxLon, err = strconv.ParseFloat(smaxlon, 64); err != nil {
|
||||||
|
err = errInvalidArgument(smaxlon)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rect = geojson.NewRect(geometry.Rect{
|
||||||
|
Min: geometry.Point{X: minLon, Y: minLat},
|
||||||
|
Max: geometry.Point{X: maxLon, Y: maxLat},
|
||||||
|
})
|
||||||
|
case "hash":
|
||||||
|
var hash string
|
||||||
|
if vs, hash, ok = tokenval(vs); !ok || hash == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
box := geohash.BoundingBox(hash)
|
||||||
|
rect = geojson.NewRect(geometry.Rect{
|
||||||
|
Min: geometry.Point{X: box.MinLng, Y: box.MinLat},
|
||||||
|
Max: geometry.Point{X: box.MaxLng, Y: box.MaxLat},
|
||||||
|
})
|
||||||
|
case "quadkey":
|
||||||
|
var key string
|
||||||
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var minLat, minLon, maxLat, maxLon float64
|
||||||
|
minLat, minLon, maxLat, maxLon, err = bing.QuadKeyToBounds(key)
|
||||||
|
if err != nil {
|
||||||
|
err = errInvalidArgument(key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rect = geojson.NewRect(geometry.Rect{
|
||||||
|
Min: geometry.Point{X: minLon, Y: minLat},
|
||||||
|
Max: geometry.Point{X: maxLon, Y: maxLat},
|
||||||
|
})
|
||||||
|
case "tile":
|
||||||
|
var sx, sy, sz string
|
||||||
|
if vs, sx, ok = tokenval(vs); !ok || sx == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if vs, sy, ok = tokenval(vs); !ok || sy == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if vs, sz, ok = tokenval(vs); !ok || sz == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var x, y int64
|
||||||
|
var z uint64
|
||||||
|
if x, err = strconv.ParseInt(sx, 10, 64); err != nil {
|
||||||
|
err = errInvalidArgument(sx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if y, err = strconv.ParseInt(sy, 10, 64); err != nil {
|
||||||
|
err = errInvalidArgument(sy)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if z, err = strconv.ParseUint(sz, 10, 64); err != nil {
|
||||||
|
err = errInvalidArgument(sz)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var minLat, minLon, maxLat, maxLon float64
|
||||||
|
minLat, minLon, maxLat, maxLon = bing.TileXYToBounds(x, y, z)
|
||||||
|
rect = geojson.NewRect(geometry.Rect{
|
||||||
|
Min: geometry.Point{X: minLon, Y: minLat},
|
||||||
|
Max: geometry.Point{X: maxLon, Y: maxLat},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
nvs = vs
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (server *Server) cmdSearchArgs(
|
func (server *Server) cmdSearchArgs(
|
||||||
fromFenceCmd bool, cmd string, vs []string, types []string,
|
fromFenceCmd bool, cmd string, vs []string, types []string,
|
||||||
) (s liveFenceSwitches, err error) {
|
) (s liveFenceSwitches, err error) {
|
||||||
|
@ -170,106 +284,11 @@ func (server *Server) cmdSearchArgs(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "bounds":
|
case "bounds", "hash", "tile", "quadkey":
|
||||||
var sminLat, sminLon, smaxlat, smaxlon string
|
vs, s.obj, err = parseRectArea(ltyp, vs)
|
||||||
if vs, sminLat, ok = tokenval(vs); !ok || sminLat == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if vs, sminLon, ok = tokenval(vs); !ok || sminLon == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if vs, smaxlat, ok = tokenval(vs); !ok || smaxlat == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if vs, smaxlon, ok = tokenval(vs); !ok || smaxlon == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var minLat, minLon, maxLat, maxLon float64
|
|
||||||
if minLat, err = strconv.ParseFloat(sminLat, 64); err != nil {
|
|
||||||
err = errInvalidArgument(sminLat)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if minLon, err = strconv.ParseFloat(sminLon, 64); err != nil {
|
|
||||||
err = errInvalidArgument(sminLon)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if maxLat, err = strconv.ParseFloat(smaxlat, 64); err != nil {
|
|
||||||
err = errInvalidArgument(smaxlat)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if maxLon, err = strconv.ParseFloat(smaxlon, 64); err != nil {
|
|
||||||
err = errInvalidArgument(smaxlon)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.obj = geojson.NewRect(geometry.Rect{
|
|
||||||
Min: geometry.Point{X: minLon, Y: minLat},
|
|
||||||
Max: geometry.Point{X: maxLon, Y: maxLat},
|
|
||||||
})
|
|
||||||
case "hash":
|
|
||||||
var hash string
|
|
||||||
if vs, hash, ok = tokenval(vs); !ok || hash == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
box := geohash.BoundingBox(hash)
|
|
||||||
s.obj = geojson.NewRect(geometry.Rect{
|
|
||||||
Min: geometry.Point{X: box.MinLng, Y: box.MinLat},
|
|
||||||
Max: geometry.Point{X: box.MaxLng, Y: box.MaxLat},
|
|
||||||
})
|
|
||||||
case "quadkey":
|
|
||||||
var key string
|
|
||||||
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var minLat, minLon, maxLat, maxLon float64
|
|
||||||
minLat, minLon, maxLat, maxLon, err = bing.QuadKeyToBounds(key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errInvalidArgument(key)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.obj = geojson.NewRect(geometry.Rect{
|
|
||||||
Min: geometry.Point{X: minLon, Y: minLat},
|
|
||||||
Max: geometry.Point{X: maxLon, Y: maxLat},
|
|
||||||
})
|
|
||||||
case "tile":
|
|
||||||
var sx, sy, sz string
|
|
||||||
if vs, sx, ok = tokenval(vs); !ok || sx == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if vs, sy, ok = tokenval(vs); !ok || sy == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if vs, sz, ok = tokenval(vs); !ok || sz == "" {
|
|
||||||
err = errInvalidNumberOfArguments
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var x, y int64
|
|
||||||
var z uint64
|
|
||||||
if x, err = strconv.ParseInt(sx, 10, 64); err != nil {
|
|
||||||
err = errInvalidArgument(sx)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if y, err = strconv.ParseInt(sy, 10, 64); err != nil {
|
|
||||||
err = errInvalidArgument(sy)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if z, err = strconv.ParseUint(sz, 10, 64); err != nil {
|
|
||||||
err = errInvalidArgument(sz)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var minLat, minLon, maxLat, maxLon float64
|
|
||||||
minLat, minLon, maxLat, maxLon = bing.TileXYToBounds(x, y, z)
|
|
||||||
s.obj = geojson.NewRect(geometry.Rect{
|
|
||||||
Min: geometry.Point{X: minLon, Y: minLat},
|
|
||||||
Max: geometry.Point{X: maxLon, Y: maxLat},
|
|
||||||
})
|
|
||||||
case "get":
|
case "get":
|
||||||
if s.clip {
|
if s.clip {
|
||||||
err = errInvalidArgument("cannot clip with get")
|
err = errInvalidArgument("cannot clip with get")
|
||||||
|
@ -326,9 +345,38 @@ func (server *Server) cmdSearchArgs(
|
||||||
s.roam.scan = scan
|
s.roam.scan = scan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(vs) != 0 {
|
|
||||||
err = errInvalidNumberOfArguments
|
var clip_rect *geojson.Rect
|
||||||
return
|
var tok, ltok string
|
||||||
|
for len(vs) > 0 {
|
||||||
|
if vs, tok, ok = tokenval(vs); !ok || tok == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.ToLower(tok) != "clipby" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if vs, tok, ok = tokenval(vs); !ok || tok == "" {
|
||||||
|
err = errInvalidNumberOfArguments
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ltok = strings.ToLower(tok)
|
||||||
|
switch ltok {
|
||||||
|
case "bounds", "hash", "tile", "quadkey":
|
||||||
|
vs, clip_rect, err = parseRectArea(ltok, vs)
|
||||||
|
if err == errNotRectangle {
|
||||||
|
err = errInvalidArgument("cannot clipby " + ltok)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.obj = clip.Clip(s.obj, clip_rect, &server.geomIndexOpts)
|
||||||
|
default:
|
||||||
|
err = errInvalidArgument("cannot clipby " + ltok)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ var errIDNotFound = errors.New("id not found")
|
||||||
var errIDAlreadyExists = errors.New("id already exists")
|
var errIDAlreadyExists = errors.New("id already exists")
|
||||||
var errPathNotFound = errors.New("path not found")
|
var errPathNotFound = errors.New("path not found")
|
||||||
var errKeyHasHooksSet = errors.New("key has hooks set")
|
var errKeyHasHooksSet = errors.New("key has hooks set")
|
||||||
|
var errNotRectangle = errors.New("not a rectangle")
|
||||||
|
|
||||||
func errInvalidArgument(arg string) error {
|
func errInvalidArgument(arg string) error {
|
||||||
return fmt.Errorf("invalid argument '%s'", arg)
|
return fmt.Errorf("invalid argument '%s'", arg)
|
||||||
|
|
|
@ -13,8 +13,10 @@ func subTestSearch(t *testing.T, mc *mockServer) {
|
||||||
runStep(t, mc, "INTERSECTS_CIRCLE", keys_INTERSECTS_CIRCLE_test)
|
runStep(t, mc, "INTERSECTS_CIRCLE", keys_INTERSECTS_CIRCLE_test)
|
||||||
runStep(t, mc, "WITHIN", keys_WITHIN_test)
|
runStep(t, mc, "WITHIN", keys_WITHIN_test)
|
||||||
runStep(t, mc, "WITHIN_CURSOR", keys_WITHIN_CURSOR_test)
|
runStep(t, mc, "WITHIN_CURSOR", keys_WITHIN_CURSOR_test)
|
||||||
|
runStep(t, mc, "WITHIN_CLIPBY", keys_WITHIN_CLIPBY_test)
|
||||||
runStep(t, mc, "INTERSECTS", keys_INTERSECTS_test)
|
runStep(t, mc, "INTERSECTS", keys_INTERSECTS_test)
|
||||||
runStep(t, mc, "INTERSECTS_CURSOR", keys_INTERSECTS_CURSOR_test)
|
runStep(t, mc, "INTERSECTS_CURSOR", keys_INTERSECTS_CURSOR_test)
|
||||||
|
runStep(t, mc, "INTERSECTS_CLIPBY", keys_INTERSECTS_CLIPBY_test)
|
||||||
runStep(t, mc, "SCAN_CURSOR", keys_SCAN_CURSOR_test)
|
runStep(t, mc, "SCAN_CURSOR", keys_SCAN_CURSOR_test)
|
||||||
runStep(t, mc, "SEARCH_CURSOR", keys_SEARCH_CURSOR_test)
|
runStep(t, mc, "SEARCH_CURSOR", keys_SEARCH_CURSOR_test)
|
||||||
runStep(t, mc, "MATCH", keys_MATCH_test)
|
runStep(t, mc, "MATCH", keys_MATCH_test)
|
||||||
|
@ -145,6 +147,50 @@ func keys_WITHIN_CURSOR_test(mc *mockServer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keys_WITHIN_CLIPBY_test(mc *mockServer) error {
|
||||||
|
jagged := `{
|
||||||
|
"type":"Polygon",
|
||||||
|
"coordinates":[[
|
||||||
|
[-122.47781753540039,37.74655746554895],
|
||||||
|
[-122.48777389526366,37.7355619376922],
|
||||||
|
[-122.4707794189453,37.73271097867418],
|
||||||
|
[-122.46528625488281,37.735969208590504],
|
||||||
|
[-122.45189666748047,37.73922729512254],
|
||||||
|
[-122.4565315246582,37.75008654795525],
|
||||||
|
[-122.46683120727538,37.75307256315459],
|
||||||
|
[-122.47781753540039,37.74655746554895]
|
||||||
|
]]
|
||||||
|
}`
|
||||||
|
|
||||||
|
return mc.DoBatch([][]interface{}{
|
||||||
|
{"SET", "mykey", "point1", "FIELD", "foo", 1, "POINT", 37.73963454585715, -122.4810791015625}, {"OK"},
|
||||||
|
{"SET", "mykey", "point2", "FIELD", "foo", 2, "POINT", 37.75130811419222, -122.47438430786133}, {"OK"},
|
||||||
|
{"SET", "mykey", "point3", "FIELD", "foo", 1, "POINT", 37.74816932695052, -122.47713088989258}, {"OK"},
|
||||||
|
{"SET", "mykey", "point4", "FIELD", "foo", 2, "POINT", 37.74503040657439, -122.47571468353271}, {"OK"},
|
||||||
|
{"SET", "other", "jagged", "OBJECT", jagged}, {"OK"},
|
||||||
|
|
||||||
|
{"WITHIN", "mykey", "IDS", "GET", "other", "jagged"}, {"[0 [point1 point4]]"},
|
||||||
|
{"WITHIN", "mykey", "IDS", "BOUNDS",
|
||||||
|
37.737734023260884, -122.47816085815431, 37.74886496155229, -122.45464324951172,
|
||||||
|
}, {"[0 [point3 point4]]"},
|
||||||
|
{"WITHIN", "mykey", "IDS", "GET", "other", "jagged", "CLIPBY", "BOUNDS",
|
||||||
|
37.737734023260884, -122.47816085815431, 37.74886496155229, -122.45464324951172,
|
||||||
|
}, {"[0 [point4]]"},
|
||||||
|
{"WITHIN", "mykey", "IDS", "BOUNDS",
|
||||||
|
37.74411415606583, -122.48034954071045, 37.7536833241461, -122.47163772583008,
|
||||||
|
}, {"[0 [point2 point3 point4]]"},
|
||||||
|
{"WITHIN", "mykey", "IDS", "GET", "other", "jagged", "CLIPBY", "BOUNDS",
|
||||||
|
37.74411415606583, -122.48034954071045, 37.7536833241461, -122.47163772583008,
|
||||||
|
}, {"[0 [point4]]"},
|
||||||
|
{"WITHIN", "mykey", "IDS", "GET", "other", "jagged",
|
||||||
|
"CLIPBY", "BOUNDS",
|
||||||
|
37.74411415606583, -122.48034954071045, 37.7536833241461, -122.47163772583008,
|
||||||
|
"CLIPBY", "BOUNDS",
|
||||||
|
37.737734023260884, -122.47816085815431, 37.74886496155229, -122.45464324951172,
|
||||||
|
}, {"[0 [point4]]"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func keys_INTERSECTS_test(mc *mockServer) error {
|
func keys_INTERSECTS_test(mc *mockServer) error {
|
||||||
return mc.DoBatch([][]interface{}{
|
return mc.DoBatch([][]interface{}{
|
||||||
{"SET", "mykey", "point1", "POINT", 37.7335, -122.4412}, {"OK"},
|
{"SET", "mykey", "point1", "POINT", 37.7335, -122.4412}, {"OK"},
|
||||||
|
@ -195,6 +241,50 @@ func keys_INTERSECTS_test(mc *mockServer) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keys_INTERSECTS_CLIPBY_test(mc *mockServer) error {
|
||||||
|
jagged := `{
|
||||||
|
"type":"Polygon",
|
||||||
|
"coordinates":[[
|
||||||
|
[-122.47781753540039,37.74655746554895],
|
||||||
|
[-122.48777389526366,37.7355619376922],
|
||||||
|
[-122.4707794189453,37.73271097867418],
|
||||||
|
[-122.46528625488281,37.735969208590504],
|
||||||
|
[-122.45189666748047,37.73922729512254],
|
||||||
|
[-122.4565315246582,37.75008654795525],
|
||||||
|
[-122.46683120727538,37.75307256315459],
|
||||||
|
[-122.47781753540039,37.74655746554895]
|
||||||
|
]]
|
||||||
|
}`
|
||||||
|
|
||||||
|
return mc.DoBatch([][]interface{}{
|
||||||
|
{"SET", "mykey", "point1", "FIELD", "foo", 1, "POINT", 37.73963454585715, -122.4810791015625}, {"OK"},
|
||||||
|
{"SET", "mykey", "point2", "FIELD", "foo", 2, "POINT", 37.75130811419222, -122.47438430786133}, {"OK"},
|
||||||
|
{"SET", "mykey", "point3", "FIELD", "foo", 1, "POINT", 37.74816932695052, -122.47713088989258}, {"OK"},
|
||||||
|
{"SET", "mykey", "point4", "FIELD", "foo", 2, "POINT", 37.74503040657439, -122.47571468353271}, {"OK"},
|
||||||
|
{"SET", "other", "jagged", "OBJECT", jagged}, {"OK"},
|
||||||
|
|
||||||
|
{"INTERSECTS", "mykey", "IDS", "GET", "other", "jagged"}, {"[0 [point1 point4]]"},
|
||||||
|
{"INTERSECTS", "mykey", "IDS", "BOUNDS",
|
||||||
|
37.737734023260884, -122.47816085815431, 37.74886496155229, -122.45464324951172,
|
||||||
|
}, {"[0 [point3 point4]]"},
|
||||||
|
{"INTERSECTS", "mykey", "IDS", "GET", "other", "jagged", "CLIPBY", "BOUNDS",
|
||||||
|
37.737734023260884, -122.47816085815431, 37.74886496155229, -122.45464324951172,
|
||||||
|
}, {"[0 [point4]]"},
|
||||||
|
{"INTERSECTS", "mykey", "IDS", "BOUNDS",
|
||||||
|
37.74411415606583, -122.48034954071045, 37.7536833241461, -122.47163772583008,
|
||||||
|
}, {"[0 [point2 point3 point4]]"},
|
||||||
|
{"INTERSECTS", "mykey", "IDS", "GET", "other", "jagged", "CLIPBY", "BOUNDS",
|
||||||
|
37.74411415606583, -122.48034954071045, 37.7536833241461, -122.47163772583008,
|
||||||
|
}, {"[0 [point4]]"},
|
||||||
|
{"INTERSECTS", "mykey", "IDS", "GET", "other", "jagged",
|
||||||
|
"CLIPBY", "BOUNDS",
|
||||||
|
37.74411415606583, -122.48034954071045, 37.7536833241461, -122.47163772583008,
|
||||||
|
"CLIPBY", "BOUNDS",
|
||||||
|
37.737734023260884, -122.47816085815431, 37.74886496155229, -122.45464324951172,
|
||||||
|
}, {"[0 [point4]]"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func keys_INTERSECTS_CURSOR_test(mc *mockServer) error {
|
func keys_INTERSECTS_CURSOR_test(mc *mockServer) error {
|
||||||
testArea := `{
|
testArea := `{
|
||||||
"type": "Polygon",
|
"type": "Polygon",
|
||||||
|
|
Loading…
Reference in New Issue