mirror of https://github.com/tidwall/tile38.git
Added BOUNDS command
It's now possible to get the combined minimum bounding rectangle for all objects in a key by issuing the command "BOUNDS key".
This commit is contained in:
parent
6e4977ac0f
commit
1d427c849f
|
@ -86,6 +86,11 @@ func (c *Collection) TotalWeight() int {
|
||||||
return c.weight
|
return c.weight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bounds returns the bounds of all the items in the collection.
|
||||||
|
func (c *Collection) Bounds() (minX, minY, maxX, maxY float64) {
|
||||||
|
return c.index.Bounds()
|
||||||
|
}
|
||||||
|
|
||||||
// ReplaceOrInsert adds or replaces an object in the collection and returns the fields array.
|
// ReplaceOrInsert adds or replaces an object in the collection and returns the fields array.
|
||||||
// If an item with the same id is already in the collection then the new item will adopt the old item's fields.
|
// If an item with the same id is already in the collection then the new item will adopt the old item's fields.
|
||||||
// The fields argument is optional.
|
// The fields argument is optional.
|
||||||
|
|
|
@ -333,7 +333,7 @@ func (c *Controller) handleInputCommand(conn *server.Conn, msg *server.Message,
|
||||||
if c.config.ReadOnly {
|
if c.config.ReadOnly {
|
||||||
return writeErr(errors.New("read only"))
|
return writeErr(errors.New("read only"))
|
||||||
}
|
}
|
||||||
case "get", "keys", "scan", "nearby", "within", "intersects", "hooks", "search", "ttl":
|
case "get", "keys", "scan", "nearby", "within", "intersects", "hooks", "search", "ttl", "bounds":
|
||||||
// read operations
|
// read operations
|
||||||
c.mu.RLock()
|
c.mu.RLock()
|
||||||
defer c.mu.RUnlock()
|
defer c.mu.RUnlock()
|
||||||
|
@ -444,6 +444,8 @@ func (c *Controller) command(msg *server.Message, w io.Writer) (res string, d co
|
||||||
res, err = c.cmdIntersects(msg)
|
res, err = c.cmdIntersects(msg)
|
||||||
case "search":
|
case "search":
|
||||||
res, err = c.cmdSearch(msg)
|
res, err = c.cmdSearch(msg)
|
||||||
|
case "bounds":
|
||||||
|
res, err = c.cmdBounds(msg)
|
||||||
case "get":
|
case "get":
|
||||||
res, err = c.cmdGet(msg)
|
res, err = c.cmdGet(msg)
|
||||||
case "keys":
|
case "keys":
|
||||||
|
|
|
@ -47,6 +47,63 @@ func orderFields(fmap map[string]int, fields []float64) []fvt {
|
||||||
sort.Sort(byField(fvs))
|
sort.Sort(byField(fvs))
|
||||||
return fvs
|
return fvs
|
||||||
}
|
}
|
||||||
|
func (c *Controller) cmdBounds(msg *server.Message) (string, error) {
|
||||||
|
start := time.Now()
|
||||||
|
vs := msg.Values[1:]
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
var key string
|
||||||
|
if vs, key, ok = tokenval(vs); !ok || key == "" {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
|
}
|
||||||
|
if len(vs) != 0 {
|
||||||
|
return "", errInvalidNumberOfArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
col := c.getCol(key)
|
||||||
|
if col == nil {
|
||||||
|
if msg.OutputType == server.RESP {
|
||||||
|
return "$-1\r\n", nil
|
||||||
|
}
|
||||||
|
return "", errKeyNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
vals := make([]resp.Value, 0, 2)
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if msg.OutputType == server.JSON {
|
||||||
|
buf.WriteString(`{"ok":true`)
|
||||||
|
}
|
||||||
|
bbox := geojson.New2DBBox(col.Bounds())
|
||||||
|
if msg.OutputType == server.JSON {
|
||||||
|
buf.WriteString(`,"bounds":`)
|
||||||
|
buf.WriteString(bbox.ExternalJSON())
|
||||||
|
} else {
|
||||||
|
vals = append(vals, resp.ArrayValue([]resp.Value{
|
||||||
|
resp.ArrayValue([]resp.Value{
|
||||||
|
resp.FloatValue(bbox.Min.Y),
|
||||||
|
resp.FloatValue(bbox.Min.X),
|
||||||
|
}),
|
||||||
|
resp.ArrayValue([]resp.Value{
|
||||||
|
resp.FloatValue(bbox.Max.Y),
|
||||||
|
resp.FloatValue(bbox.Max.X),
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
switch msg.OutputType {
|
||||||
|
case server.JSON:
|
||||||
|
buf.WriteString(`,"elapsed":"` + time.Now().Sub(start).String() + "\"}")
|
||||||
|
return buf.String(), nil
|
||||||
|
case server.RESP:
|
||||||
|
var oval resp.Value
|
||||||
|
oval = vals[0]
|
||||||
|
data, err := oval.MarshalRESP()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Controller) cmdGet(msg *server.Message) (string, error) {
|
func (c *Controller) cmdGet(msg *server.Message) (string, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
|
@ -176,6 +176,18 @@
|
||||||
"since": "1.0.0",
|
"since": "1.0.0",
|
||||||
"group": "keys"
|
"group": "keys"
|
||||||
},
|
},
|
||||||
|
"BOUNDS": {
|
||||||
|
"summary": "Get the combined bounds of all the objects in a key",
|
||||||
|
"complexity": "O(1)",
|
||||||
|
"arguments":[
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"since": "1.3.0",
|
||||||
|
"group": "keys"
|
||||||
|
},
|
||||||
"GET": {
|
"GET": {
|
||||||
"summary": "Get the object of an id",
|
"summary": "Get the object of an id",
|
||||||
"complexity": "O(1)",
|
"complexity": "O(1)",
|
||||||
|
|
|
@ -338,6 +338,18 @@ var commandsJSON = `{
|
||||||
"since": "1.0.0",
|
"since": "1.0.0",
|
||||||
"group": "keys"
|
"group": "keys"
|
||||||
},
|
},
|
||||||
|
"BOUNDS": {
|
||||||
|
"summary": "Get the combined bounds of all the objects in a key",
|
||||||
|
"complexity": "O(1)",
|
||||||
|
"arguments":[
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"since": "1.3.0",
|
||||||
|
"group": "keys"
|
||||||
|
},
|
||||||
"GET": {
|
"GET": {
|
||||||
"summary": "Get the object of an id",
|
"summary": "Get the object of an id",
|
||||||
"complexity": "O(1)",
|
"complexity": "O(1)",
|
||||||
|
|
|
@ -99,6 +99,11 @@ func (ix *Index) Count() int {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bounds returns the minimum bounding rectangle of all items in the index.
|
||||||
|
func (ix *Index) Bounds() (MinX, MinY, MaxX, MaxY float64) {
|
||||||
|
return ix.r.Bounds()
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveAll removes all items from the index.
|
// RemoveAll removes all items from the index.
|
||||||
func (ix *Index) RemoveAll() {
|
func (ix *Index) RemoveAll() {
|
||||||
ix.r.RemoveAll()
|
ix.r.RemoveAll()
|
||||||
|
|
Loading…
Reference in New Issue