Some little experiment with a coverage index to speed up spatial queries if backend has no Z order support.

This commit is contained in:
Sascha L. Teichmann
2015-07-21 22:01:10 +02:00
parent 470b47f70a
commit 1921b8211b
5 changed files with 281 additions and 76 deletions

View File

@ -45,20 +45,6 @@ func (c Coord) String() string {
return fmt.Sprintf("(%d, %d, %d)", c.X, c.Y, c.Z)
}
func minComponent(a, b int16) int16 {
if a < b {
return a
}
return b
}
func maxComponent(a, b int16) int16 {
if a > b {
return a
}
return b
}
func clipComponent(x int16) int16 {
if x < minValue {
return minValue
@ -78,16 +64,16 @@ func ClipCoord(c Coord) Coord {
func MinCoord(a, b Coord) Coord {
return Coord{
X: minComponent(a.X, b.X),
Y: minComponent(a.Y, b.Y),
Z: minComponent(a.Z, b.Z)}
X: min16(a.X, b.X),
Y: min16(a.Y, b.Y),
Z: min16(a.Z, b.Z)}
}
func MaxCoord(a, b Coord) Coord {
return Coord{
X: maxComponent(a.X, b.X),
Y: maxComponent(a.Y, b.Y),
Z: maxComponent(a.Z, b.Z)}
X: max16(a.X, b.X),
Y: max16(a.Y, b.Y),
Z: max16(a.Z, b.Z)}
}
// DecodeStringFromBytes constructs a database key out of byte slice.

82
common/coverage.go Normal file
View File

@ -0,0 +1,82 @@
package common
import "sync"
type zRange struct {
y1 int16
y2 int16
xRange *Span
}
type Coverage3D struct {
pool *SpanPool
zRanges map[int16]*zRange
mu sync.RWMutex
}
type Range struct {
Z int16
Y1 int16
Y2 int16
X1 int16
X2 int16
}
func NewCoverage3D() *Coverage3D {
return &Coverage3D{
pool: NewSpanPool(),
zRanges: map[int16]*zRange{}}
}
func (s2d *Coverage3D) Insert(c Coord) {
s2d.mu.Lock()
defer s2d.mu.Unlock()
zr := s2d.zRanges[c.Z]
if zr == nil {
xr := s2d.pool.Alloc()
xr.From = int32(c.X)
xr.To = int32(c.X)
xr.Next = nil
s2d.zRanges[c.Z] = &zRange{
y1: c.Y,
y2: c.Y,
xRange: xr}
return
}
zr.xRange = s2d.pool.Insert(zr.xRange, int32(c.X), 0)
if c.Y < zr.y1 {
zr.y1 = c.Y
}
if c.Y > zr.y2 {
zr.y2 = c.Y
}
}
func (s2d *Coverage3D) Query(c1, c2 Coord) []Range {
c1, c2 = MinCoord(c1, c2), MaxCoord(c1, c2)
s2d.mu.RLock()
defer s2d.mu.RUnlock()
r := make([]Range, 0, 32)
for z := c1.Z; z <= c2.Z; z++ {
zr := s2d.zRanges[z]
if zr == nil || c1.Y > zr.y2 || c2.Y < zr.y1 {
continue
}
y1, y2 := max16(c1.Y, zr.y1), min16(c2.Y, zr.y2)
for xr := zr.xRange; xr != nil && xr.From <= int32(c2.X); xr = xr.Next {
if xr.To < int32(c1.X) {
continue
}
r = append(r, Range{
Z: z,
Y1: y1,
Y2: y2,
X1: max16(c1.X, int16(xr.From)),
X2: min16(c2.X, int16(xr.To))})
}
}
return r
}

36
common/math.go Normal file
View File

@ -0,0 +1,36 @@
package common
func max(a, b int) int {
if a > b {
return a
}
return b
}
func max32(a, b int32) int32 {
if a > b {
return a
}
return b
}
func min32(a, b int32) int32 {
if a < b {
return a
}
return b
}
func max16(a, b int16) int16 {
if a > b {
return a
}
return b
}
func min16(a, b int16) int16 {
if a < b {
return a
}
return b
}

View File

@ -48,20 +48,6 @@ func (yo *YOrder) Reset() {
yo.blocks = yo.blocks[0:0]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func max32(a, b int32) int32 {
if a > b {
return a
}
return b
}
func copyData(data []byte) []byte {
l := len(data)
ndata := make([]byte, l, max(l, 8*1024))